I'm trying to learn how to make entity lists and for now I'm starting with a projectile list for Player 1. My projectiles worked fine when everything was just hardcoded and static but that's a bad way of actually making something functional so I wanted to learn how to do it 'properly'. The problem I'm having is that my projectiles aren't showing up and I can't figure out what's going on, any help would be greatly appreciated. FWIW I'm using ASM6 compiler.
Entity List Variables:
Player 1 - Fire Vulcan Subroutine
Gets called when the player presses the A button
Note: prj_vulcan_lvl0_sprite is the metasprite data
Main Part of loop which updates sprite stuff once per frame
Note: JSR buildSpriteTable just calls p1_updateProjectiles subroutine for now so I didn't include it's code.
Update Player 1's Projectiles
Should be updating any active projectiles and copying their sprite data into the sprite table (which is getting DMA'd to the PPU every frame)
Entity List Variables:
Code:
.enum $0400 ;start lists in RAM ($0400-$07FF) - 1024 bytes
;Player 1's projectile variables (8x5 = 40 bytes)
;Bytes = Is Active, Type, Level, Xpos, Ypos
p1_projectile1 .dsb 5 ;Player 1's projectiles
p1_projectile2 .dsb 5
p1_projectile3 .dsb 5
p1_projectile4 .dsb 5
p1_projectile5 .dsb 5
p1_projectile6 .dsb 5
p1_projectile7 .dsb 5
p1_projectile8 .dsb 5
.ende ;end Entity lists
;Player 1's projectile variables (8x5 = 40 bytes)
;Bytes = Is Active, Type, Level, Xpos, Ypos
p1_projectile1 .dsb 5 ;Player 1's projectiles
p1_projectile2 .dsb 5
p1_projectile3 .dsb 5
p1_projectile4 .dsb 5
p1_projectile5 .dsb 5
p1_projectile6 .dsb 5
p1_projectile7 .dsb 5
p1_projectile8 .dsb 5
.ende ;end Entity lists
Player 1 - Fire Vulcan Subroutine
Gets called when the player presses the A button
Note: prj_vulcan_lvl0_sprite is the metasprite data
Code:
p1_fireVulcan:
LDX #$00
LDY #$00
p1_fireVulcanLoop:
LDA p1_projectile1, x
CMP #PRJ_INACTIVE
BEQ p1_initVulcanProjectile ;check for an inactive projectile slot, then spawn a projectile
INX ;Increment X 5 times because each projectile slot is 5 bytes wide
INX
INX
INX
INX
CPX #PLAYER_NUM_PRJ_BYTES ;Compare X to 40
BNE p1_fireVulcanLoop
JMP p1_fireVulcanDone ;IF no inactive projectile slot is found skip the rest of the subroutine
p1_initVulcanProjectile:
;SET projectile to ACTIVE
LDA #PRJ_ACTIVE
STA p1_projectile1, x
;SET projectile type to VULCAN
INX
LDA #PRJ_VULCAN
STA p1_projectile1, x
;Determine & SET projectile level (which metasprite to use)
;For now just default to a Level 0 projectile
INX
LDA #PRJ_LVL0
STA p1_projectile1, x
;Determine & SET Xpos
INX
LDY #$03
LDA p1_x
CLC
ADC prj_vulcan_lvl0_sprite, y
STA p1_projectile1, x
;Determine & SET Ypos
INX
LDY #$00
LDA p1_y
SEC
SBC prj_vulcan_lvl0_sprite, y
STA p1_projectile1, x
p1_fireVulcanDone:
RTS ;end p1_fireVulcan
LDX #$00
LDY #$00
p1_fireVulcanLoop:
LDA p1_projectile1, x
CMP #PRJ_INACTIVE
BEQ p1_initVulcanProjectile ;check for an inactive projectile slot, then spawn a projectile
INX ;Increment X 5 times because each projectile slot is 5 bytes wide
INX
INX
INX
INX
CPX #PLAYER_NUM_PRJ_BYTES ;Compare X to 40
BNE p1_fireVulcanLoop
JMP p1_fireVulcanDone ;IF no inactive projectile slot is found skip the rest of the subroutine
p1_initVulcanProjectile:
;SET projectile to ACTIVE
LDA #PRJ_ACTIVE
STA p1_projectile1, x
;SET projectile type to VULCAN
INX
LDA #PRJ_VULCAN
STA p1_projectile1, x
;Determine & SET projectile level (which metasprite to use)
;For now just default to a Level 0 projectile
INX
LDA #PRJ_LVL0
STA p1_projectile1, x
;Determine & SET Xpos
INX
LDY #$03
LDA p1_x
CLC
ADC prj_vulcan_lvl0_sprite, y
STA p1_projectile1, x
;Determine & SET Ypos
INX
LDY #$00
LDA p1_y
SEC
SBC prj_vulcan_lvl0_sprite, y
STA p1_projectile1, x
p1_fireVulcanDone:
RTS ;end p1_fireVulcan
Main Part of loop which updates sprite stuff once per frame
Note: JSR buildSpriteTable just calls p1_updateProjectiles subroutine for now so I didn't include it's code.
Code:
;Setup sprite pointer - For now always draw player 1, so the pointer always begins pointing to the first available slot after the player 1 metasprite
LDA #PLAYER_NUMSPRITETILES
STA sprite_pointer
LDA #$02
STA sprite_pointer + #$01 ;Write $0209 to sprite pointer
;setup the sprite counter - For now always draw player 1, start the counter at 36 (9 sprites x 4 bytes)
LDA #$24
STA sprite_counter
JSR buildSpriteTable
LDA #PLAYER_NUMSPRITETILES
STA sprite_pointer
LDA #$02
STA sprite_pointer + #$01 ;Write $0209 to sprite pointer
;setup the sprite counter - For now always draw player 1, start the counter at 36 (9 sprites x 4 bytes)
LDA #$24
STA sprite_counter
JSR buildSpriteTable
Update Player 1's Projectiles
Should be updating any active projectiles and copying their sprite data into the sprite table (which is getting DMA'd to the PPU every frame)
Code:
;Player Projectile Data -> Is Active, Type, Level, Xpos, Ypos
p1_updateProjectiles:
;Loop through entity list
;Check each projectile for ACTIVE, update if TRUE
LDX #$00
LDY #$00
p1_checkPrjActiveLoop:
LDA p1_projectile1, x
CMP #PRJ_ACTIVE
BEQ p1_updateCurrentProjectile ;check for active projectile, IF TRUE then update it
p1_continuePrjActive:
INX ;Increment X 5 times because each projectile slot is 5 bytes wide
INX
INX
INX
INX
CPX #PLAYER_NUM_PRJ_BYTES ;Compare X to 40
BNE p1_checkPrjActiveLoop ;If not 40, continue loop
BEQ p1_updateProjectilesDone ;If 40, end updates
p1_updateCurrentProjectile:
TXA
TAY ;Transfer X to Y so I can update projectiles without affecting X (which is used in the loop)
INY ;INY to check TYPE
;Check TYPE here ->skip to appropriate label (Either VULCAN or SIDE)
;For now don't check type, only testing with Vulcan
INY ;INY to check LEVEL
;Check LEVEL here ->skip to appropriate label
;For now don't check level, assume it's level 0 since that's what I'm testing with
INY ;INY to check X pos
;Move projectile:
;For now only move X (which is what Vulcan Projectiles do)
;Check if it's within screen bounds (IF not, set it inactive and go back through loop)
LDA p1_projectile1, y
CLC
ADC #PRJ_VULCAN_SPEED
BCS p1_updateCurrentProjectile_setInactive ;IF A rolled over, set the projectile inactive. IF NOT continue
STA p1_projectile1, y
;Check for collision with enemies here
;IF TRUE deal damage to enemy, spawn explosion, set Inactive
;Copy metasprite data to sprite table
;For now just copy a Vulcan Level 0 metasprite to the sprite table for testing
p1_updateCurrentProjectile_copy:
TXA
TAY
;Player Projectile Data = 5 bytes -> Is Active, Type, Level, Xpos, Ypos
;Sprite = 4 bytes -> Ypos, Tile Number, Attributes, Xpos
INY
INY
INY
INY
LDA p1_projectile1, y
STA (sprite_pointer) ;Store sprite Ypos to sprite table
INC sprite_pointer
LDA prj_vulcan_lvl0_sprite + #$01
STA (sprite_pointer) ;Store sprite TileNum to sprite table
INC sprite_pointer
LDA prj_vulcan_lvl0_sprite + #$02
STA (sprite_pointer) ;Store sprite Attributes to sprite table
INC sprite_pointer
DEY
LDA p1_projectile1, y
STA (sprite_pointer) ;Store Xpos to sprite table
INC sprite_pointer
LDA sprite_counter
CLC
ADC #$04
STA sprite_counter ;Add 4 to sprite_counter (used to keep track of used sprite slots, and for blanking unused sprite slots)
JMP p1_continuePrjActive
p1_updateCurrentProjectile_setInactive:
TXA
TAY
LDA #PRJ_INACTIVE ;Set projectile to inactive state
STA p1_projectile1, y
INY
LDA #PRJ_VULCAN ;For now just set it to vulcan
STA p1_projectile1, y
INY
LDA #PRJ_LVL0 ;For now set the level to 0
STA p1_projectile1, y
INY
LDA #$FF
STA p1_projectile1, y
INY
STA p1_projectile1, y ;Set the X&Ypos to 255
JMP p1_continuePrjActive
p1_updateProjectilesDone:
RTS ;end p1_updateProjectiles
p1_updateProjectiles:
;Loop through entity list
;Check each projectile for ACTIVE, update if TRUE
LDX #$00
LDY #$00
p1_checkPrjActiveLoop:
LDA p1_projectile1, x
CMP #PRJ_ACTIVE
BEQ p1_updateCurrentProjectile ;check for active projectile, IF TRUE then update it
p1_continuePrjActive:
INX ;Increment X 5 times because each projectile slot is 5 bytes wide
INX
INX
INX
INX
CPX #PLAYER_NUM_PRJ_BYTES ;Compare X to 40
BNE p1_checkPrjActiveLoop ;If not 40, continue loop
BEQ p1_updateProjectilesDone ;If 40, end updates
p1_updateCurrentProjectile:
TXA
TAY ;Transfer X to Y so I can update projectiles without affecting X (which is used in the loop)
INY ;INY to check TYPE
;Check TYPE here ->skip to appropriate label (Either VULCAN or SIDE)
;For now don't check type, only testing with Vulcan
INY ;INY to check LEVEL
;Check LEVEL here ->skip to appropriate label
;For now don't check level, assume it's level 0 since that's what I'm testing with
INY ;INY to check X pos
;Move projectile:
;For now only move X (which is what Vulcan Projectiles do)
;Check if it's within screen bounds (IF not, set it inactive and go back through loop)
LDA p1_projectile1, y
CLC
ADC #PRJ_VULCAN_SPEED
BCS p1_updateCurrentProjectile_setInactive ;IF A rolled over, set the projectile inactive. IF NOT continue
STA p1_projectile1, y
;Check for collision with enemies here
;IF TRUE deal damage to enemy, spawn explosion, set Inactive
;Copy metasprite data to sprite table
;For now just copy a Vulcan Level 0 metasprite to the sprite table for testing
p1_updateCurrentProjectile_copy:
TXA
TAY
;Player Projectile Data = 5 bytes -> Is Active, Type, Level, Xpos, Ypos
;Sprite = 4 bytes -> Ypos, Tile Number, Attributes, Xpos
INY
INY
INY
INY
LDA p1_projectile1, y
STA (sprite_pointer) ;Store sprite Ypos to sprite table
INC sprite_pointer
LDA prj_vulcan_lvl0_sprite + #$01
STA (sprite_pointer) ;Store sprite TileNum to sprite table
INC sprite_pointer
LDA prj_vulcan_lvl0_sprite + #$02
STA (sprite_pointer) ;Store sprite Attributes to sprite table
INC sprite_pointer
DEY
LDA p1_projectile1, y
STA (sprite_pointer) ;Store Xpos to sprite table
INC sprite_pointer
LDA sprite_counter
CLC
ADC #$04
STA sprite_counter ;Add 4 to sprite_counter (used to keep track of used sprite slots, and for blanking unused sprite slots)
JMP p1_continuePrjActive
p1_updateCurrentProjectile_setInactive:
TXA
TAY
LDA #PRJ_INACTIVE ;Set projectile to inactive state
STA p1_projectile1, y
INY
LDA #PRJ_VULCAN ;For now just set it to vulcan
STA p1_projectile1, y
INY
LDA #PRJ_LVL0 ;For now set the level to 0
STA p1_projectile1, y
INY
LDA #$FF
STA p1_projectile1, y
INY
STA p1_projectile1, y ;Set the X&Ypos to 255
JMP p1_continuePrjActive
p1_updateProjectilesDone:
RTS ;end p1_updateProjectiles