The reason the built-in sprite collision detection register ($D01E) isn't used is because it requires a (metric?) tonne more code to work out which sprites are involved in the collision. This means that I wouldn't have been able to (without wasting time and memory on that extra code) have any of the meanie sprites overlapping without there being issues in detection - they would have had to stay clear of each other to keep things simple and this would limit the game play and level layout somewhat.
Thanks to Jason 'T.M.R.' Kelk for pointing me in the direction of some online GitHub resources which, almost unbelievably, I read and then proceeded to write a software based collision that worked first time.
All that's happening in the detection code is that the x-y coordinates of the main player sprite are grabbed from the sprite table and invisible x-y points are calculated within the sprite and stored in collision variables. These variables are then tested against the x-y coordinates of the meanie sprites, grabbed from the same sprite table. When an overlap occurs, there is a virtual 'collision'.
From there, in my code, energy is then taken a away from the player, although I have tweaked the timer so that it's possible to be 'colliding with a meanie for some time without losing too much energy in one go.
Here is the collision code as I finished coding today, which will obviously change quite a bit as new features are added, but for now works fine...
; player to enemy sprites subroutine ----------------------------
; software based collision detection... no $d01e here!!!
player_collision
lda #$00 ; set the death flag to 0
sta ply_death_flag
lda sprite_x+$00 ; setup a 'bounding box'
sec ; around the player sprite
sbc #$04 ; for software collision
sta coll_temp+$00 ; detection
clc ; grab the some x positions
adc #$09 ; for our player sprite which
sta coll_temp+$01 ; is sprite 0!
lda sprite_y+$00 ; and do the same for some y
sec ; positions of sprite 0
sbc #$0a
sta coll_temp+$02 ; the x and y positions are
clc ; stored in the 'coll_temp'
adc #$16 ; labels
sta coll_temp+$03
ldx #$00
enem_colls_loop
ldy colls_timer ; first load up the collision timer
iny ; and increase it by '1'
cpy #$08 ; is the timer equal to '8' yet?
bne coll_tmr_skip ; no? go down to coll_tmr_skip
; and skip collision checking
lda sprite_x+$01,x ; now grab the x postion of each sprite
cmp coll_temp+$00 ; from the sprite table
bcc enem_colls_skip ; and check against our 'bounding box'
cmp coll_temp+$01 ; coordinates to see if they
bcs enem_colls_skip ; overlap...
lda sprite_y+$01,x ; and do the same for the y coordinates
cmp coll_temp+$02
bcc enem_colls_skip ; if no coordinates overlap, skip down
cmp coll_temp+$03 ; to 'enem_colls_skip'
bcs enem_colls_skip
; if some coordinates overlap, collision!
dec ply_energy ; decrease the player energy flag by 1
jsr energy_bar ; redraw the energy bar
lda ply_energy ; is the player out of energy?
cmp #$00 ; yes?
beq energy_out ; skip down to 'energy_out'
enem_colls_skip
inx
cpx #$07
bne enem_colls_loop
ldy #$00 ; load x register with '0'
coll_tmr_skip ; to reset collision timer and...
sty colls_timer ; store x register to colls_timer
rts ; go back to main game loop
energy_out
lda #$01 ; load the player death flag with
sta ply_death_flag ; 1 because all the energy is gone!
; then...
rts ; go back to main game loop where
; player will be killed!!!! MWHAAAA!
Once compiled and running in WinVICE, it looks a little like this...
Next diary entry...

No comments:
Post a Comment