Story Screen
The story screen shows a basic story on 2 pages. Afterwards, it sends the player to the gameplay game state.
Initiating up the Story Screen
In the InitStoryState
we’ll just going to turn on the LCD. Most of the game state’s logic will occur in its update function.
The text macros file is included so our story text has the proper character maps.
INCLUDE "src/main/utils/hardware.inc"
INCLUDE "src/main/utils/macros/text-macros.inc"
SECTION "StoryStateASM", ROM0
InitStoryState::
; Turn the LCD on
ld a, LCDCF_ON | LCDCF_BGON|LCDCF_OBJON | LCDCF_OBJ16
ld [rLCDC], a
ret
Updating the Story Screen
Here’s the data for our story screen. We have this defined just above our UpdateStoryState
function:
Story:
.Line1 db "the galatic empire", 255
.Line2 db "rules the galaxy", 255
.Line3 db "with an iron", 255
.Line4 db "fist.", 255
.Line5 db "the rebel force", 255
.Line6 db "remain hopeful of", 255
.Line7 db "freedoms light", 255
The story text is shown using a typewriter effect. This effect is done similarly to the “press a to play” text that was done before, but here we wait for 3 vertical blank phases between writing each letter, giving some additional delay.
You could bind this to a variable and make it configurable via an options screen too!
For this effect, we’ve defined a function in our “src/main/utils/text-utils.asm” file:
DrawText_WithTypewriterEffect::
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Wait a small amount of time
; Save our count in this variable
ld a, 3
ld [wVBlankCount], a
; Call our function that performs the code
call WaitForVBlankFunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check for the end of string character 255
ld a, [hl]
cp 255
ret z
; Write the current character (in hl) to the address
; on the tilemap (in de)
ld a, [hl]
ld [de], a
; move to the next character and next background tile
inc hl
inc de
jp DrawText_WithTypewriterEffect
We’ll call the DrawText_WithTypewriterEffect
function exactly how we called the DrawTextTilesLoop
function. We’ll pass this function which tile to start on in de, and the address of our text in hl.
We’ll do that four times for the first page, and then wait for the A button to be pressed:
UpdateStoryState::
; Call Our function that typewrites text onto background/window tiles
ld de, $9821
ld hl, Story.Line1
call DrawText_WithTypewriterEffect
; Call Our function that typewrites text onto background/window tiles
ld de, $9861
ld hl, Story.Line2
call DrawText_WithTypewriterEffect
; Call Our function that typewrites text onto background/window tiles
ld de, $98A1
ld hl, Story.Line3
call DrawText_WithTypewriterEffect
; Call Our function that typewrites text onto background/window tiles
ld de, $98E1
ld hl, Story.Line4
call DrawText_WithTypewriterEffect
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Wait for A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Save the passed value into the variable: mWaitKey
; The WaitForKeyFunction always checks against this vriable
ld a, PADF_A
ld [mWaitKey], a
call WaitForKeyFunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Once the user presses the A button, we want to show the second page. To avoid any lingering “leftover” letters, we’ll clear the background. All this function does is turn off the LCD, fill our background tilemap with the first tile, then turn back on the lcd. We’ve defined this function in the “src/main/utils/background.utils.asm” file:
include "src/main/utils/hardware.inc"
SECTION "Background", ROM0
ClearBackground::
; Turn the LCD off
xor a
ld [rLCDC], a
ld bc, 1024
ld hl, $9800
ClearBackgroundLoop:
xor a
ld [hli], a
dec bc
ld a, b
or c
jp nz, ClearBackgroundLoop
; Turn the LCD on
ld a, LCDCF_ON | LCDCF_BGON|LCDCF_OBJON | LCDCF_OBJ16
ld [rLCDC], a
ret
Getting back to our Story Screen: After we’ve shown the first page and cleared the background, we’ll do the same thing for page 2:
; Call Our function that typewrites text onto background/window tiles
ld de, $9821
ld hl, Story.Line5
call DrawText_WithTypewriterEffect
; Call Our function that typewrites text onto background/window tiles
ld de, $9861
ld hl, Story.Line6
call DrawText_WithTypewriterEffect
; Call Our function that typewrites text onto background/window tiles
ld de, $98A1
ld hl, Story.Line7
call DrawText_WithTypewriterEffect
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Wait for A
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Save the passed value into the variable: mWaitKey
; The WaitForKeyFunction always checks against this vriable
ld a, PADF_A
ld [mWaitKey], a
call WaitForKeyFunction
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
With our story full shown, we’re ready to move onto the next game state: Gameplay. We’ll end our UpdateStoryState
function by updating our game state variable and jump back to the NextGameState
label like previously discussed.
ld a, 2
ld [wGameState],a
jp NextGameState