From ae857d302cd6f81c130b216f5dcc16655a09b4ac Mon Sep 17 00:00:00 2001 From: Miquel Sabaté Solà Date: Tue, 13 May 2025 14:57:15 +0200 Subject: Implement the base for moving bullets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This establishes a way for bullets to move, be displayed as independent sprites, cycle these sprites, and check for the collision on the background. This is still lacking the collision check with enemies and has some obvious bugs that will be fixed on the next commits. Signed-off-by: Miquel Sabaté Solà --- src/driver.s | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 160 insertions(+), 2 deletions(-) (limited to 'src/driver.s') diff --git a/src/driver.s b/src/driver.s index 4c2220f..c428475 100644 --- a/src/driver.s +++ b/src/driver.s @@ -18,7 +18,13 @@ PAUSE_TIMER_VALUE = (HZ / 3) zp_pause_timer = $32 - ;; Switch from the title screen to the main street. Note that this function + ;; Number of sprites available for sprite cycling. + SPRITE_CYCLING_BYTES = (64 - Player::PLAYER_SPRITES_COUNT) * 4 + + ;; TODO + zp_next_bullet_cycle = $33 + + ;; Switch from the title screen to the main screen. Note that this function ;; is to be called with the PPU disabled. If that's not the case, then it ;; will set the proper values to disable it on the next `nmi` call and set ;; the `title over` flag. With that, call again this function so the @@ -80,11 +86,15 @@ @load_player: jsr Player::init + jsr Bullets::init ;; Initialize pause timer. lda #0 sta zp_pause_timer + ;; Initialize variables for sprite cycling. + sta zp_next_bullet_cycle + @game: ;; Check if the player is toggling the `pause` state. lda #(Joypad::BUTTON_START | Joypad::BUTTON_SELECT) @@ -131,8 +141,156 @@ beq @do_update rts + ;; This is the actual meat of the main game, which updates the state of + ;; the player, bullets, enemies, etc. @do_update: - JAL Player::update + jsr Player::update + jsr Bullets::update + JAL sprite_cycling + ;; TODO: fall through? + .endproc + + .proc sprite_cycling + ;; The 'y' register will contain the index on OAM of the sprite to be + ;; allocated. + ldy #(Player::PLAYER_SPRITES_COUNT * 4) + + ;; The 'x' register will index from the different sprite pools. + ldx zp_next_bullet_cycle + lda Bullets::zp_bullets_pool_base, x + + ;; Is this a valid bullet? + cmp #$FF + beq @after_first_bullet + + ;; It is a valid bullet! Set it now. + lda Bullets::zp_bullets_pool_base + 1, x + sta $200, y + iny + + ;; The tile selection depends on how many moves the bullet has done. + lda Bullets::zp_bullets_pool_base, x + and #%01111111 + cmp #Bullets::BULLET_LAST_TRANSITION + bcs @last_bullet_tile + cmp #Bullets::BULLET_FIRST_TRANSITION + bcs @mid_bullet_tile + lda #$0E + bne @set_bullet_tile + @mid_bullet_tile: + lda #$0F + bne @set_bullet_tile + @last_bullet_tile: + lda #$1E + @set_bullet_tile: + sta $200, y + + iny + lda #0 + sta $200, y + iny + lda Bullets::zp_bullets_pool_base + 2, x + sta $200, y + iny + + @after_first_bullet: + ;; Save the index that was considered for the first bullet. + stx Globals::zp_tmp0 + + ;; Increase the index for the bullets cycling. If wrapping is detected, + ;; then it resets this value back to zero. + inx + inx + inx + cpx #Bullets::BULLETS_POOL_CAPACITY_BYTES + bne @set_next_bullets_cycle + ldx #0 + @set_next_bullets_cycle: + stx zp_next_bullet_cycle + + ;; TODO: ensure 1 enemy + iny + iny + iny + iny + + ;; TODO: ensure 1 item + iny + iny + iny + iny + + ;; TODO: rest of bullets + ldx #0 + @rest_o_bullets: + cpx #Bullets::BULLETS_POOL_CAPACITY_BYTES + beq @rest_o_enemies + cpx Globals::zp_tmp0 + bne @do_bullet + inx + inx + inx + cpx #Bullets::BULLETS_POOL_CAPACITY_BYTES + beq @rest_o_enemies + @do_bullet: + lda Bullets::zp_bullets_pool_base, x + cmp #$FF + beq @next_bullet + + lda Bullets::zp_bullets_pool_base + 1, x + sta $200, y + iny + + ;; The tile selection depends on how many moves the bullet has done. + lda Bullets::zp_bullets_pool_base, x + and #%01111111 + cmp #Bullets::BULLET_LAST_TRANSITION + bcs @other_last_bullet_tile + cmp #Bullets::BULLET_FIRST_TRANSITION + bcs @other_mid_bullet_tile + lda #$0E + bne @other_set_bullet_tile + @other_mid_bullet_tile: + lda #$0F + bne @other_set_bullet_tile + @other_last_bullet_tile: + lda #$1E + @other_set_bullet_tile: + sta $200, y + + iny + lda #0 + sta $200, y + iny + lda Bullets::zp_bullets_pool_base + 2, x + sta $200, y + iny + + @next_bullet: + inx + inx + inx + jmp @rest_o_bullets + + @rest_o_enemies: + ;; TODO: rest of enemies + ;; TODO: rest of items + + ;; We are done with all the sprites we wanted to allocat. Now let's + ;; clear out the rest of the slots just in case there was some leftover + ;; from a past sprite. + lda #$EF + @check_cycle_end: + cpy #SPRITE_CYCLING_BYTES + bne @reset_sprite + rts + @reset_sprite: + sta $200, y + iny + iny + iny + iny + jmp @check_cycle_end ;TODO: maybe just bne? .endproc .ifdef PAL -- cgit v1.2.3