Of course a game isn't a game without some challenge. Therefore we need enemies. Since we have some neat little level build code why not use it for enemies as well?
We add a new level primitive type LD_OBJECT which adds objects (= sprites). We use it for both player and enemies. A new table SPRITE_ACTIVE is added to see if a sprite is used (and which type).
One central function to this is FindEmptySpriteSlot. It iterates over the sprite active table and looks for a free slot to use. If there is a free slot we set the object active, apply the object startup values and use the previously created CalcSpritePosFromCharPos to place the sprite.
Note that we don't plan to use more than 8 objects so we can directly map object to sprites.
Find an empty slot:
;------------------------------------------------------------
;Looks for an empty sprite slot, returns in X
;#1 in A when empty slot found, #0 when full
;------------------------------------------------------------
!zone FindEmptySpriteSlot
FindEmptySpriteSlot
ldx #0
.CheckSlot
lda SPRITE_ACTIVE,x
beq .FoundSlot
inx
cpx #8
bne .CheckSlot
lda #0
rts
.FoundSlot
lda #1
rts
How we add an object during level buildup:
.Object
;X pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM1
;Y pos
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM2
;type
iny
lda (ZEROPAGE_POINTER_1),y
sta PARAM3
;store y for later
tya
pha
;add object to sprite array
jsr FindEmptySpriteSlot
beq .NoFreeSlot
lda PARAM3
sta SPRITE_ACTIVE,x
;PARAM1 and PARAM2 hold x,y already
jsr CalcSpritePosFromCharPos
;enable sprite
lda BIT_TABLE,x
ora VIC_SPRITE_ENABLE
sta VIC_SPRITE_ENABLE
lda #SPRITE_PLAYER
sta SPRITE_POINTER_BASE,x
.NoFreeSlot
jmp .NextLevelData