We have the building blocks of a game here, but we’re still lacking player input. A game that plays itself isn’t very much fun, so let’s fix that.
Paste this code below your
Memcpy, this is a function that can be reused from different places, using the
Input: ; Poll half the controller ld a, P1F_GET_BTN call .onenibble ld b, a ; B7-4 = 1; B3-0 = unpressed buttons ; Poll the other half ld a, P1F_GET_DPAD call .onenibble swap a ; A3-0 = unpressed directions; A7-4 = 1 xor a, b ; A = pressed buttons + directions ld b, a ; B = pressed buttons + directions ; And release the controller ld a, P1F_GET_NONE ldh [rP1], a ; Combine with previous wCurKeys to make wNewKeys ld a, [wCurKeys] xor a, b ; A = keys that changed state and a, b ; A = keys that changed to pressed ld [wNewKeys], a ld a, b ld [wCurKeys], a ret .onenibble ldh [rP1], a ; switch the key matrix call .knownret ; burn 10 cycles calling a known ret ldh a, [rP1] ; ignore value while waiting for the key matrix to settle ldh a, [rP1] ldh a, [rP1] ; this read counts or a, $F0 ; A7-4 = 1; A3-0 = unpressed keys .knownret ret
Unfortunately, reading input on the Game Boy is fairly involved (as you can see!), and it would be quite difficult to explain what this function does right now. So, I ask that you make an exception, and trust me that this function does read input. Alright? Good!
Now that we know how to use functions, let’s call the
UpdateKeys function in our main loop to read user input.
UpdateKeys writes the held buttons to a location in memory that we called
wCurKeys, which we can read from after the function returns.
Because of this, we only need to call
UpdateKeys once per frame.
This is important, because not only is it faster to reload the inputs that we’ve already processed, but it also means that we will always act on the same inputs, even if the player presses or releases a button mid-frame.
First, let’s set aside some room for the two variables that
UpdateKeys will use; paste this at the end of the
SECTION "Input Variables", WRAM0 wCurKeys: db wNewKeys: db
Each variable must reside in RAM, and not ROM, because ROM is “Read-Only” (so you can’t modify it).
Additionally, each variable only needs to be one byte large, so we use
db (“Define Byte”) to reserve one byte of RAM for each.
We’re going to use the
and opcode, which we can use to set the zero flag (
z) to the value of the bit.
We can use this along with the
PADF constants in hardware.inc to read a particular key.
Main: ld a, [rLY] cp 144 jp nc, Main WaitVBlank2: ld a, [rLY] cp 144 jp c, WaitVBlank2 ; Check the current keys every frame and move left or right. call Input ; First, check if the left button is pressed. CheckLeft: ld a, [wCurKeys] and a, PADF_LEFT jp z, CheckRight Left: ; Move the paddle one pixel to the left. ld a, [_OAMRAM + 1] dec a ; If we've already hit the edge of the playfield, don't move. cp a, 15 jp z, Main ld [_OAMRAM + 1], a jp Main ; Then check the right button. CheckRight: ld a, [wCurKeys] and a, PADF_RIGHT jp z, Main Right: ; Move the paddle one pixel to the right. ld a, [_OAMRAM + 1] inc a ; If we've already hit the edge of the playfield, don't move. cp a, 105 jp z, Main ld [_OAMRAM + 1], a jp Main
Now, if you compile the project, you should be able to move the paddle left and right using the d-pad!! Hooray, we have the beginnings of a game!