Switch to use Add/Update sprite and rely on Render to place sprites in frame

This commit is contained in:
Lucas Scharenbroich 2021-10-31 15:44:03 -05:00
parent 532af93538
commit 83ea7921ff

View File

@ -41,6 +41,7 @@ DOWN_ARROW equ $0A
; Set up our level data ; Set up our level data
jsr BG0SetUp jsr BG0SetUp
; jsr TileAnimInit ; jsr TileAnimInit
jsr SetLimits
; Allocate room to load data ; Allocate room to load data
; jsr MovePlayerToOrigin ; Put the player at the beginning of the map ; jsr MovePlayerToOrigin ; Put the player at the beginning of the map
@ -50,16 +51,31 @@ DOWN_ARROW equ $0A
ldal OneSecondCounter ldal OneSecondCounter
sta oldOneSecondCounter sta oldOneSecondCounter
; Add a player sprite ; Initialize the sprite's global position (this is tracked outside of the tile engine)
lda #0 lda #16
sta PlayerX sta PlayerGlobalX
sta PlayerXOld lda MaxGlobalY
lda #14 sec
sta PlayerY lda #40 ; 32 for tiles, 8 for sprite
sta PlayerYOld sta PlayerGlobalY
lda #1
sta PlayerXVel stz PlayerXVel
sta PlayerYVel stz PlayerYVel
; Add a sprite to the engine and save it's sprite ID
jsr UpdatePlayerLocal
lda #3 ; 8x8 sprite, tile ID = 3
ldx PlayerX
ldy PlayerY
jsl AddSprite
bcc :sprite_ok
brl Exit ; If we could not allocate a sprite, exit
:sprite_ok
sta PlayerID
; Draw the initial screen
lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render lda #DIRTY_BIT_BG0_REFRESH ; Redraw all of the tiles on the next Render
tsb DirtyBits tsb DirtyBits
@ -70,64 +86,118 @@ DOWN_ARROW equ $0A
; the play field tiles. ; the play field tiles.
EvtLoop EvtLoop
jsl ReadControl jsl ReadControl
; Check the buttons first
pha
bit #$0100
beq :no_jump
lda PlayerStanding
beq :no_jump
lda #$FFF8
sta PlayerYVel
:no_jump
pla
and #$007F ; Ignore the buttons for now and #$007F ; Ignore the buttons for now
cmp #'q' cmp #'q'
bne :not_q bne :not_q
brl Exit brl Exit
:not_q :not_q
cmp #'x'
bne :not_x
lda #$0001
jsr UpdatePlayerPos
bra :4
:not_x
cmp #'y' cmp #'d'
bne :not_y bne :not_d
lda #$0002 lda StartX
jsr UpdatePlayerPos cmp MaxBG0X
bra :4 bcs :do_render
:not_y inc
jsl SetBG0XPos
bra :do_render
:not_d
cmp #'r' cmp #'a'
beq :3 bne :not_a
lda StartX
beq :do_render
dec
jsl SetBG0XPos
bra :do_render
:not_a
cmp #'n' cmp #'s'
beq :2 bne :not_s
stz KeyState lda StartY
bra :4 cmp MaxBG0Y
:2 bcs :do_render
lda KeyState ; Wait for key up / key down inc
bne :4 jsl SetBG0YPos
lda #1 bra :do_render
sta KeyState :not_s
:3
lda #$0003 cmp #'w'
jsr UpdatePlayerPos bne :not_w
lda StartY
beq :do_render
dec
jsl SetBG0YPos
bra :do_render
:not_w
; Do j,l to move the character left/right
cmp #'j'
bne :not_j
lda PlayerXVel
bpl :pos_xvel
cmp #$FFFA
bcc :not_j
:pos_xvel dec
sta PlayerXVel
bra :do_render
:not_j
cmp #'l'
bne :not_l
lda PlayerXVel
bmi :neg_xvel
cmp #6
bcs :not_l
:neg_xvel inc
sta PlayerXVel
bra :do_render
:not_l
; Update the camera position
:do_render
; jsr UpdatePlayerPos ; Moves in global cordinates
; jsr UpdateCameraPos ; Moves the screen
; jsr UpdatePlayerLocal ; Gets local sprite coordinates
; lda PlayerID
; ldx PlayerX
; ldy PlayerY
; jsl UpdateSprite ; Move the sprite to this local position
:4
; Draw the sprite in the sprite plane ; Draw the sprite in the sprite plane
ldx PlayerX ; ldx PlayerX
ldy PlayerY ; ldy PlayerY
jsl GetSpriteVBuffAddr ; jsl GetSpriteVBuffAddr
tax ; put in X ; tax ; put in X
ldy #3*128 ; draw the 3rd tile as a sprite ; ldy #3*128 ; draw the 3rd tile as a sprite
stx PlayerLastPos ; save for erasure ; stx PlayerLastPos ; save for erasure
jsl DrawTileSprite ; jsl DrawTileSprite
; Now the sprite has been drawn. Enqueue the dirty tiles. We blindly add the potential ; Now the sprite has been drawn. Enqueue the dirty tiles. We blindly add the potential
; dirty tiles and rely on PushDirtyTile to elimate duplicates quickly ; dirty tiles and rely on PushDirtyTile to elimate duplicates quickly
ldx PlayerX ; ldx PlayerX
ldy PlayerY ; ldy PlayerY
jsr MakeDirtySprite8x8 ; jsr MakeDirtySprite8x8
; The dirty tile queue has been written to; apply it to the code field ; The dirty tile queue has been written to; apply it to the code field
jsl ApplyTiles ; jsl ApplyTiles
; Let's see what it looks like! ; Let's see what it looks like!
@ -146,20 +216,14 @@ EvtLoop
; Erase the sprites that moved ; Erase the sprites that moved
ldx PlayerLastPos ; Delete the sprite because it moved ; ldx PlayerLastPos ; Delete the sprite because it moved
jsl EraseTileSprite ; jsl EraseTileSprite
ldx PlayerXOld ; Remove the sprite flag from the tiles
ldy PlayerYOld ; at the old position.
jsr ClearSpriteFlag8x8
; Add the tiles that the sprite was previously at as well. ; Add the tiles that the sprite was previously at as well.
ldx PlayerXOld ; ldx PlayerXOld
ldy PlayerYOld ; ldy PlayerYOld
jsr MakeDirtyTile8x8 ; jsr MakeDirtyTile8x8
; tax ; tax
; ldy PlayerY ; ldy PlayerY
@ -180,7 +244,10 @@ Exit
bcs Fatal bcs Fatal
Fatal brk $00 Fatal brk $00
MyPalette dw $0000,$0777,$0F31,$0E51,$00A0,$02E3,$0BF1,$0FA4,$0FD7,$0EE6,$0F59,$068F,$01CE,$09B9,$0EDA,$0EEE MyPalette dw $068F,$0EDA,$0000,$068F,$0BF1,$00A0,$0EEE,$0777,$01CE,$0FA4,$0F59,$0D40,$02E3,$09B9,$0F93,$0FD7
PlayerGlobalX ds 2
PlayerGlobalY ds 2
PlayerID ds 2 PlayerID ds 2
PlayerX ds 2 PlayerX ds 2
@ -191,72 +258,168 @@ PlayerLastPos ds 2
PlayerXVel ds 2 PlayerXVel ds 2
PlayerYVel ds 2 PlayerYVel ds 2
KeyState ds 2 KeyState ds 2
PlayerStanding ds 2
MaxGlobalX ds 2
MaxGlobalY ds 2
MaxBG0X ds 2
MaxBG0Y ds 2
oldOneSecondCounter ds 2 oldOneSecondCounter ds 2
frameCount ds 2 frameCount ds 2
PLAYER_X_MIN equ 65536-3 PLAYER_X_MIN equ 0
PLAYER_X_MAX equ 159 PLAYER_X_MAX equ 160-4
PLAYER_Y_MIN equ 65536-7 PLAYER_Y_MIN equ 0
PLAYER_Y_MAX equ 199 PLAYER_Y_MAX equ 200-8
; Need to use signed comparisons here EMPTY_TILE equ $0029 ; the tile that makes up the background
; @see http://6502.org/tutorials/compare_beyond.html
UpdatePlayerPosX AdjustLocalX
lda PlayerX ; Move the player sprite a bit
sta PlayerXOld
clc clc
adc PlayerXVel adc StartXMod164
sta PlayerX cmp #164
bcc *+5
; Compate PlayerX with the X_MIN value. BMI if PlayerX < X_MIN, BPL is PlayerX >= X_MIN sbc #164
cmp #PLAYER_X_MIN
beq :x_flip
cmp #PLAYER_X_MAX
bne :x_ok
:x_flip
lda PlayerXVel
eor #$FFFF
inc
sta PlayerXVel
:x_ok
rts rts
AdjustLocalY
UpdatePlayerPosY
lda PlayerY
sta PlayerYOld
clc clc
adc PlayerYVel adc StartYMod208
sta PlayerY cmp #208
bcc *+5
cmp #PLAYER_Y_MIN sbc #208
beq :y_flip
cmp #PLAYER_Y_MAX
bne :y_ok
:y_flip
lda PlayerYVel
eor #$FFFF
inc
sta PlayerYVel
:y_ok
rts rts
SetLimits
lda TileMapWidth
asl
asl
sta MaxGlobalX
sec
sbc ScreenWidth
sta MaxBG0X
lda TileMapHeight
asl
asl
asl
sta MaxGlobalY
sec
sbc ScreenHeight
sta MaxBG0Y
rts
; Set the scroll position based on the global cooridinate of the player
; Try to center the player on the screen
UpdateCameraPos
lda ScreenWidth
lsr
sta tmp0
lda PlayerGlobalX
sec
sbc tmp0
bpl :x_pos
lda #0
:x_pos cmp MaxBG0X
bcc :x_ok
lda MaxBG0X
:x_ok jsl SetBG0XPos
lda ScreenHeight
lsr
sta tmp0
lda PlayerGlobalY
sec
sbc tmp0
bpl :y_pos
lda #0
:y_pos cmp MaxBG0Y
bcc :y_ok
lda MaxBG0Y
:y_ok jsl SetBG0YPos
rts
; Convert the global coordinates to adjusted local coordinated (compensating for wrap-around)
UpdatePlayerLocal
lda PlayerGlobalX
sec
sbc StartX
jsr AdjustLocalX
sta PlayerX
lda PlayerGlobalY
sec
sbc StartY
jsr AdjustLocalY
sta PlayerY
rts
; Simple updates with gravity and collisions. It's important that eveything in this
; subroutine be done against
UpdatePlayerPos UpdatePlayerPos
pha stz PlayerStanding
bit #$0001 lda PlayerYVel
beq :skip_x bmi :no_ground_check
jsr UpdatePlayerPosX
:skip_x pla ; Check if the player is standing on the ground at their current local position
bit #$0002
beq :skip_y
jsr UpdatePlayerPosY
:skip_y ldx PlayerX
rts lda PlayerY
clc
adc #8
tay
jsr GetTileAt
cmp #EMPTY_TILE
beq :no_ground_check
lda PlayerGlobalY
and #$fff8
sta PlayerGlobalY
stz PlayerYVel
lda #1
sta PlayerStanding
:no_ground_check
lda PlayerGlobalY
clc
adc PlayerYVel
bpl *+5
lda #0
cmp MaxGlobalY
bcc *+5
lda MaxGlobalY
sta PlayerGlobalY
lda PlayerGlobalX
clc
adc PlayerXVel
bpl *+5
lda #0
cmp MaxGlobalX
bcc *+5
lda MaxGlobalX
sta PlayerGlobalX
lda PlayerXVel
beq :no_dxv
bpl :pos_dxv
inc
bra :no_dxv
:pos_dxv
dec
:no_dxv
sta PlayerXVel
lda PlayerYVel
inc
bmi :is_neg
cmp #4
bcs :too_fast
:is_neg
sta PlayerYVel
:too_fast
rts
; Takes a signed playfield position (including off-screen coordinates) and a size and marks ; Takes a signed playfield position (including off-screen coordinates) and a size and marks
; the tiles that are impacted by this shape. The main job of this subroutine is to ensure ; the tiles that are impacted by this shape. The main job of this subroutine is to ensure
@ -306,7 +469,31 @@ MarkTiles
rts rts
; X = coordinate
; Y = coordinate
GetTileAt
txa
bmi :out
lsr
lsr
tax
tya
bmi :out
lsr
lsr
lsr
tay
jsl GetTileStoreOffset
tax
ldal TileStore+TS_TILE_ID,x
rts
:out
lda #EMPTY_TILE
rts
; X = coordinate ; X = coordinate
; Y = coordinate ; Y = coordinate
@ -397,62 +584,6 @@ MakeDirtyTile8x8
plx plx
rts rts
ClearSpriteFlag8x8
phx
phy
txa
lsr
lsr
tax
tya
lsr
lsr
lsr
tay
jsr ClearSpriteFlag ; top-left
lda 3,s
clc
adc #3
lsr
lsr
tax
jsr ClearSpriteFlag ; top-right
lda 1,s
clc
adc #7
lsr
lsr
lsr
tay
jsr ClearSpriteFlag ; bottom-right
lda 3,s
lsr
lsr
tax
jsr ClearSpriteFlag ; bottom-left
ply
plx
rts
; x = column
; y = row
ClearSpriteFlag
phx
phy
jsl GetTileStoreOffset
tax
lda #0
stal TileStore+TS_SPRITE_FLAG,x
ply
plx
rts
MakeDirtyTile MakeDirtyTile
phx phx
phy phy