A C64 Game - Step 12


One of the more complex steps. And also one I someday need to heavily optimize. The player can now shoot an enemy.

The central function for this is FireShot. We don't use a bullet but insta-shot. However walls should block the shot as well. This means, we need to take the current player direction and position, and work our way to the left/right until we hit an enemy or a wall.
Since there's no direct collision involved we take the character pos of the player, add or decrease the x pos and compare against all alive enemies pos. Rinse and repeat until done.



I've given the enemies 5 HP, and the player has a shot delay of 10 frames. Therefore it takes a while for the enemy to disappear (best tested with the box on top). If the player is purple the shot delay is active.


We start with adding a fire delay to PlayerControl:


          lda PLAYER_SHOT_PAUSE
bne .FirePauseActive

lda #1
sta VIC_SPRITE_COLOR
lda #$10
bit $dc00
bne .NotFirePushed
jsr FireShot
jmp .FireDone

.FirePauseActive
dec PLAYER_SHOT_PAUSE
.FireDone
.NotFirePushed



This simply checks for PLAYER_SHOT_PAUSE. If it is higher than 0 the player is still pausing. If so the counter is decreased and the fire function skipped. If the counter is zero, we check the fire button and if pressed call the FireShot routine.

The FireShot routine is not that complicated, however it's taking its processing time. First set the fire pause to 10 frames. Mark the player as shooting by changing his color.

Now the hard part. There is no visible bullet. So we take the current player position, increase/decrease X and check for a blocking char or a hittable enemy. If the bullet is blocked, done. If an enemy is hit, decrease its health by one point. Once the health is down to zero the enemy is removed.

!zone FireShotFireShot
;frame delay until next shot
lda #10
sta PLAYER_SHOT_PAUSE

;mark player as shooting
lda #4
sta VIC_SPRITE_COLOR
ldy SPRITE_CHAR_POS_Y
dey
lda SCREEN_LINE_OFFSET_TABLE_LO,y
sta ZEROPAGE_POINTER_1
lda SCREEN_LINE_OFFSET_TABLE_HI,y
sta ZEROPAGE_POINTER_1 + 1

ldy SPRITE_CHAR_POS_X

.ShotContinue
lda SPRITE_DIRECTION
beq .ShootRight

;shooting left
dey
lda (ZEROPAGE_POINTER_1),y
jsr IsCharBlocking
bne .ShotDone

jmp .CheckHitEnemy

.ShootRight
iny
lda (ZEROPAGE_POINTER_1),y
jsr IsCharBlocking
bne .ShotDone

.CheckHitEnemy
;hit an enemy?
ldx #1
.CheckEnemy
stx PARAM2
lda SPRITE_ACTIVE,x
beq .CheckNextEnemy
tax
lda IS_TYPE_ENEMY,x
beq .CheckNextEnemy

;sprite pos matches on x?
ldx PARAM2
sty PARAM1
lda SPRITE_CHAR_POS_X,x
cmp PARAM1
bne .CheckNextEnemy

;sprite pos matches on y?
lda SPRITE_CHAR_POS_Y,x
cmp SPRITE_CHAR_POS_Y
beq .EnemyHit

;sprite pos matches on y + 1?
clc
adc #1
cmp SPRITE_CHAR_POS_Y
beq .EnemyHit

;sprite pos matches on y - 1?
sec
sbc #2
cmp SPRITE_CHAR_POS_Y
bne .CheckNextEnemy

.EnemyHit
;enemy hit!
dec SPRITE_HP,x
lda SPRITE_HP,x
beq .EnemyKilled
jmp .ShotDone

.EnemyKilled
jsr RemoveObject
jmp .ShotDone

.CheckNextEnemy
ldx PARAM2
inx
cpx #8
bne .CheckEnemy

jmp .ShotContinue

.ShotDone
rts




step12.zip