Thursday, 25 July 2019

Software Collision Detection

Following on from yesterday, I've decided to move away from using the C64 built-in collision detection almost straight away since I know other routines (such as the energy bar) are working.

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