diff options
| author | Miquel Sabaté Solà <msabate@suse.com> | 2023-10-24 17:40:19 +0200 |
|---|---|---|
| committer | Miquel Sabaté Solà <mikisabate@gmail.com> | 2025-02-04 20:58:36 +0100 |
| commit | 149020464517ff3d021eef5ccd50d3939ad463e6 (patch) | |
| tree | 056ec1919fe0c0d515e7a0a414916307b768ef84 /space/src/states/player.s | |
| parent | be2414f5b11b182998fca7e87712ff0502c8ee93 (diff) | |
| download | code.nes-149020464517ff3d021eef5ccd50d3939ad463e6.tar.gz code.nes-149020464517ff3d021eef5ccd50d3939ad463e6.zip | |
Lay out a proper structure for the project
Let's divide things by topic instead of a broad "examples" directory.
This will allow for simple files to co-exist together with full-blown
projects.
Signed-off-by: Miquel Sabaté Solà <msabate@suse.com>
Diffstat (limited to 'space/src/states/player.s')
| -rw-r--r-- | space/src/states/player.s | 356 |
1 files changed, 356 insertions, 0 deletions
diff --git a/space/src/states/player.s b/space/src/states/player.s new file mode 100644 index 0000000..a43f61e --- /dev/null +++ b/space/src/states/player.s @@ -0,0 +1,356 @@ +;;; +;; Player state: movement, animation, etc. The following memory addresses are +;; reserved for the player: +;; -> $30-$3F: internal data. +;; -> $0200-$0207: OAM data. +;;; +.scope Player + ;; TODO: change names of pos_x and signed_x et al + m_pos_x = $30 + m_pos_y = $31 + m_velocity_x = $32 + m_velocity_y = $33 + m_target_velocity_x = $34 + m_target_velocity_y = $35 + m_signed_x = $36 ; NOTE ! + m_signed_y = $38 ; NOTE ! + + ;; Initializes the player by initializing its internal data and loading some + ;; values of the sprite itself. + .proc init + ;; Initialize position + subpixel. + lda #$B0 + sta m_signed_y + lda #$00 + sta m_signed_y + 1 + lda #$7A + sta m_signed_x + lda #$F0 + sta m_signed_x + 1 + + ;; Initialize velocity. + lda #0 + sta m_velocity_x + sta m_velocity_y + sta m_target_velocity_x + sta m_target_velocity_y + + ;; The player itself is built with two identical sprites placed side by + ;; side, where the second one is flipped horizontally. Thus, the player + ;; takes up the first two slots on OAM data ($0200-$0207). Here we only + ;; need to select the sprite and the attributes, since the position will + ;; be updated on each game loop. Hence, here we select the sprite + ;; located at #0 on the pattern table, and then we set for the second + ;; one the horizontal flip bit for the attributes. + lda #0 + sta $0201 ; First sprite select. + sta $0205 ; Second sprite select. + lda #%00000000 + sta $0202 ; First sprite attributes. + lda #%01000000 + sta $0206 ; Second sprite attributes. + + rts + .endproc + + ;; Contains all the subroutines that have to deal with computing the + ;; movement of the sprite depending on the previous state, the buttons being + ;; pressed, the current position, etc. + .scope Movement + .proc update + jsr set_target_velocity + jsr accelerate + jsr apply_velocity + jsr position_to_coordinates + rts + .endproc + + ;; Set the target velocity for the X and Y axis given the current button + ;; presses. + .proc set_target_velocity + ;; The target velocity depends on whether B was pressed or not. + ;; Depending on that we will set the x index to point to one element + ;; of the velocity tables below or to another. + ldx #0 + lda #Joypad::BUTTON_B + and Joypad::m_buttons1 + beq @target_check_right + inx + @target_check_right: + ;; The algorithm from here on is pretty straight-forward. Check the + ;; right button. If it was not pressed jump to the left check. If it + ;; was pressed load the target velocity on the x-axis from the given + ;; table and jump into the arrow-up check. + lda #Joypad::BUTTON_RIGHT + and Joypad::m_buttons1 + beq @target_check_left + lda positive_velocity, x + sta m_target_velocity_x + jmp @target_check_up + + @target_check_left: + ;; Similar to before: if it was not pressed, then set the target + ;; velocity to 0, otherwise set the proper value and jump to the up + ;; check. + lda #Joypad::BUTTON_LEFT + and Joypad::m_buttons1 + beq @target_no_x + lda negative_velocity, x + sta m_target_velocity_x + jmp @target_check_up + + @target_no_x: + ;; None of the buttons on the X-axis were pressed. Set the target + ;; velocity to 0. + lda #0 + sta m_target_velocity_x + ;; NOTE: walkthrough + + @target_check_up: + ;; Same as before but we return early if it was pressed, otherwise + ;; we go into the arrow-down check. + lda #Joypad::BUTTON_UP + and Joypad::m_buttons1 + beq @target_check_down + lda negative_velocity, x + sta m_target_velocity_y + rts + + @target_check_down: + ;; If down was not pressed, go to the "no_y" case, otherwise return + ;; early after setting the proper Y target velocity. + lda #Joypad::BUTTON_DOWN + and Joypad::m_buttons1 + beq @target_no_y + lda positive_velocity, x + sta m_target_velocity_y + rts + + @target_no_y: + ;; None of the buttons on the Y-axis were pressed. Set the target + ;; velocity to 0. + lda #0 + sta m_target_velocity_y + rts + + ;; TODO + positive_velocity: + ;; $18: 0001 | 1000 + ;; $28: 0010 | 1000 + .byte $18, $28 + negative_velocity: + ;; $E8: 1110 | 1000 + ;; $D8: 1101 | 1000 + .byte $E8, $D8 + .endproc + + ;; TODO: give it a closer look + .proc accelerate + lda m_velocity_x + sec + sbc m_target_velocity_x + bne @accelerate_x_check_greater + jmp @accelerate_y + @accelerate_x_check_greater: + bmi @accelerate_x_check_lesser + dec m_velocity_x + jmp @accelerate_y + @accelerate_x_check_lesser: + inc m_velocity_x + + @accelerate_y: + lda m_velocity_y + sec + sbc m_target_velocity_y + bne @accelerate_y_check_greater + rts + @accelerate_y_check_greater: + bmi @accelerate_y_check_lesser + dec m_velocity_y + rts + @accelerate_y_check_lesser: + inc m_velocity_y + rts + .endproc + + ;; TODO: give it a closer look + .proc apply_velocity + lda m_velocity_x + bmi @apply_negative_velocity_x + + clc + adc m_signed_x + sta m_signed_x + lda #0 ;NOTE: adding possible carry! + adc m_signed_x + 1 + sta m_signed_x + 1 + jmp @apply_velocity_y + + @apply_negative_velocity_x: + lda #0 + sec + sbc m_velocity_x + sta $00 + lda m_signed_x + sec + sbc $00 + sta m_signed_x + lda m_signed_x + 1 + sbc #0 + sta m_signed_x + 1 + ;; NOTE: walkthrough + + @apply_velocity_y: + lda m_velocity_y + bmi @apply_negative_velocity_y + + clc + adc m_signed_y + sta m_signed_y + lda #0 + adc m_signed_y + 1 + sta m_signed_y + 1 + rts + + @apply_negative_velocity_y: + lda #0 + sec + sbc m_velocity_y + sta $00 + lda m_signed_y + sec + sbc $00 + sta m_signed_y + lda m_signed_y + 1 + sbc #0 + sta m_signed_y + 1 + rts + .endproc + + .proc position_to_coordinates + jsr position_to_coordinates_x + jsr position_to_coordinates_y + + rts + .endproc + + .proc position_to_coordinates_x + ;; Convert the fixed point position coordinate into screen coordinates + lda m_signed_x + sta $00 + lda m_signed_x + 1 + sta $01 + lsr $01 + ror $00 + lsr $01 + ror $00 + lsr $01 + ror $00 + lsr $01 + ror $00 + ; Assume that everything is fine and save the sprite position + lda $00 + sta m_pos_x + + lda m_velocity_x + bmi @position_from_negative_velocity + + lda $01 + bne @bound_upper_x + lda $00 + cmp #239 + bcs @bound_upper_x + rts + @bound_upper_x: + lda #$EF + sta m_pos_x + lda #$0E + sta m_signed_x + 1 + lda #$F0 + sta m_signed_x + lda #0 + sta m_velocity_x + rts + @position_from_negative_velocity: + lda m_signed_x + 1 + bmi @bound_lower_x + rts + @bound_lower_x: + lda #0 + sta m_signed_x + sta m_signed_x + 1 + sta m_pos_x + sta m_velocity_x + rts + .endproc + + .proc position_to_coordinates_y + ;; Convert the fixed point position coordinate into screen coordinates + lda m_signed_y + sta $00 + lda m_signed_y + 1 + sta $01 + lsr $01 + ror $00 + lsr $01 + ror $00 + lsr $01 + ror $00 + lsr $01 + ror $00 + ; Assume that everything is fine and save the sprite position + lda $00 + sta m_pos_y + + lda m_velocity_y + bmi @position_from_negative_velocity_y + + lda $01 + bne @bound_upper_y + lda $00 + cmp #239 + bcs @bound_upper_y + rts + @bound_upper_y: + lda #$EF + sta m_pos_y + lda #$0E + sta m_signed_y + 1 + lda #$F0 + sta m_signed_y + lda #0 + sta m_velocity_y + rts + @position_from_negative_velocity_y: + lda m_signed_y + 1 + bmi @bound_lower_y + rts + @bound_lower_y: + lda #0 + sta m_signed_y + sta m_signed_y + 1 + sta m_pos_y + sta m_velocity_y + rts + .endproc + .endscope + + ;; Functions related to the rendering and manipulation of the sprite itself. + .scope Sprite + ;; Update the sprite on OAM memory according to what we have in the + ;; internal data stored in $30-$3F. + .proc update + lda m_pos_y + sta $200 + sta $204 + + lda m_pos_x + sta $203 + clc + adc #8 + sta $207 + + rts + .endproc + .endscope +.endscope |
