I am only a few days into assembly programming and am messing about trying to create 'lunar lander' like physics.
I've achieved something that works, but it feels janky/sticky. Considering the point of the game is to land softly, I am finding it difficult to do that when testing the game.
There is actually nothing to land on yet, but its easy to see how difficult it would be to land if you play.
The ROM is here: https://whoshotdk.co.uk/project.nes (D-pad controls)
I've read about using two bytes for both position and velocity, one for the integer part and one for the fractional part. I thank the nes-god-king Rainwarrior for that idea. I have attempted to implement that. I'm fairly sure I've got it wrong, probably in the 'euler integration (lol)' part of the code, where I'm attempting to do a 16-bit addition.
The main game loop is posted below.
I'd really appreciate a clear explanation of how to do '16-bit' position/velocity physics. As I could not find that on the 'net already, I'm sure it'd be appreciated by others too! Unless my Google-foo has failed me.
Thanks!
Dave
Code: Select all
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; these are the constants im using
MAX_VELOCITY_X = $20
MAX_VELOCITY_Y = $20
PLAYER_THRUSTER_X = $20
PLAYER_THRUSTER_Y = $20
GRAVITY = $10
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; zero page segment
playerX: .res 2 ; high = integer, low = fraction
playerY: .res 2 ; high = integer, low = fraction
playerVX: .res 2 ; high = integer, low = fraction
playerVY: .res 2 ; high = integer, low = fraction
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; code segment, main loop...
Update:
; copy to sprites
LDA playerX
STA $0203
LDA playerY
STA $0200
; player input
JSR ReadInput
LDA input
AND #BUTTON_LEFT
BEQ :+ ; skip if button not pressed
LDA playerVX + 1 ; dec fraction byte
SEC
SBC #PLAYER_THRUSTER_X
STA playerVX + 1
BCS :+ ; skip if fraction byte overflowed
LDA playerVX ; dec high byte
SEC
SBC #$01
STA playerVX
:
LDA input
AND #BUTTON_RIGHT
BEQ :+ ; skip if button not pressed
LDA playerVX + 1 ; inc fraction byte
CLC
ADC #PLAYER_THRUSTER_X
STA playerVX + 1
BCC :+ ; skip if fraction byte overflowed
LDA playerVX ; inc high byte
CLC
ADC #$01
STA playerVX
:
LDA input
AND #BUTTON_UP
BEQ :+ ; skip if button not pressed
LDA playerVY + 1 ; dec fraction byte
SEC
SBC #PLAYER_THRUSTER_Y
STA playerVY + 1
BCS :+ ; skip if fraction byte overflowed
LDA playerVY ; dec high byte
SEC
SBC #$01
STA playerVY
:
LDA input
AND #BUTTON_DOWN
BEQ :+ ; skip if button not pressed
LDA playerVY + 1 ; inc fraction byte
CLC
ADC #PLAYER_THRUSTER_Y
STA playerVY + 1
BCC :+ ; skip if fraction byte overflowed
LDA playerVY ; inc high byte
CLC
ADC #$01
STA playerVY
:
; gravity
LDA playerVY + 1
CLC
ADC #GRAVITY
STA playerVY + 1
BCC :+ ; skip if fraction byte overflowed
LDA playerVY ; inc high byte
CLC
ADC #$01
STA playerVY
:
; limit velocity
; x
LDA playerVX
BEQ :++ ; skip if velocity = 0
BPL :+ ; skip if velocity > 0
CMP #($FF - MAX_VELOCITY_X + 1) ; velocity < 0, compare against maximum
BPL :+ ; skip if velocity < maximum
LDA #($FF - MAX_VELOCITY_X + 1) ; velocity > maximum, clamp it
STA playerVX
JMP :++
:
CMP #MAX_VELOCITY_X ; velocity > 0, compare against maximum
BMI :+ ; skip if velocity < maximum
LDA #MAX_VELOCITY_X ; velocity > maximum, clamp it
STA playerVX
:
; y
LDA playerVY
BEQ :++ ; skip if velocity = 0
BPL :+ ; skip if velocity > 0
CMP #($FF - MAX_VELOCITY_Y + 1) ; velocity < 0, compare against maximum
BPL :+ ; skip if velocity < maximum
LDA #($FF - MAX_VELOCITY_Y + 1) ; velocity > maximum, clamp it
STA playerVY
JMP :++
:
CMP #MAX_VELOCITY_Y ; velocity > 0, compare against maximum
BMI :+ ; skip if velocity < maximum
LDA #MAX_VELOCITY_Y ; velocity > maximum, clamp it
STA playerVY
:
; euler integration
LDA playerVX + 1 ; velocity x fraction
CLC
ADC playerX + 1
STA playerX + 1
LDA playerVX ; velocity x high
CLC
ADC playerX
STA playerX
LDA playerVY + 1 ; velocity y fraction
CLC
ADC playerY + 1
STA playerY + 1
LDA playerVY ; velocity y high
CLC
ADC playerY
STA playerY
; debug
LDA playerVY
STA $F0
LDA playerVY + 1
STA $F1
; iterate
JSR WaitVBlank
JMP Update