前回にひきつづきチュートリアルをすすめていきます。
https://gbdev.io/gb-asm-tutorial/part2/input.html
Input
UpdateKeys:
; 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
さっそく関数です。これは解読するの大変でした(笑)。まずニブルというのは4bitのデータで半バイトをさします。P1F_GET_BTN を書き込むと下位4bitにボタンに関する値が入ります。ただ、すぐに入るとは限らず、安定するまで3回読み出しています。
上位4ビットに1をいれて返却。こんどは P1F_GET_DPAD を設定すると、十字パッドの値が下位4ビットに入ります。押している状態が0です。これを上位ニブルと下位ニブルをswapで反転して先ほどのあった値とXORをとると、上位のニブルにボタンに関するビットの反転が、下位のニブルが十字パッドに関する値の反転が格納され、これを ワークエリアに保存しています。XORにすることにより、押した状態が1になります。
wNewKeys は新しくかわった値、wCurKeys は今の値が入ります。
これをVBlank中に1回呼んでおけば、使いまわせる。
call .knownret しているのは、書き込んでから読み出せるようになるまで時間がかかるため、時間稼ぎをしているようです。call & ret は10 cycle かかるらしい。
この関数はいつでも使えそう。入力を読み取るのでも、アセンブラだと全然違いますね。
でもなんとか理解できました。
次回
次回はボールが登場。衝突のロジックも出てくるようです。