User Tools

Site Tools


base:sprite_collision_detection

Individual sprite 'boxes' for collision detection

by Achim

The regular way of detecting a sprite to sprite collision is to define a box around the sprite, which means you add an offset to the sprite's y and x values to get y2 and x2.

In most cases the 'one size fits all' approach will work, as long as all sprites in the game have a similar size. But with different sprite sizes (e.g. a big space ship and a small bullet) it's better to work with individual boxes for accurate results.

Setup

Set up sprite tables (for eight sprites):

spritey:	.byte	$00, $00, $00, $00, $00, $00, $00, $00
spritex:	.byte 	$00, $00, $00, $00, $00, $00, $00, $00
spritemsb:	.byte	$00, $00, $00, $00, $00, $00, $00, $00

The main program will use these tables to move the sprites and the irq will read the values to update the VIC registers every frame.

Next step is an offset table with four offset values for figuring out y1, y2, x1 and x2. Here's an example sprite:

Spritey and spritex declare the upper left corner of the sprite.
y coordinates of red box: y1= y+3px and y2= y1+12px
x coordinates of red box: x1= x+8px and x2= x+16px (use x again to figure out x2 for easier msb handling.)

			
offsettable:	.byte	03, 12, 08, 16,		//the two y and two x offset values
	                ...    			//and so on for all sprites...

Finally you need tables for y1, y2, x1 and x2:

spritey1:	.byte	$00, $00, $00, $00, $00, $00, $00, $00
spritex1:	.byte 	$00, $00, $00, $00, $00, $00, $00, $00
spritemsb1:	.byte	$00, $00, $00, $00, $00, $00, $00, $00
						
spritey2:	.byte	$00, $00, $00, $00, $00, $00, $00, $00
spritex2:	.byte 	$00, $00, $00, $00, $00, $00, $00, $00
spritemsb2:	.byte	$00, $00, $00, $00, $00, $00, $00, $00		

Calculation

In this example the y-reg has to point at the correct position of 'offsettable' and x-reg at the correct position of 'spritey', 'spritey1' etc.

		lda spritey,x             //fetch y
		clc
		adc offsettable,y         //add first offset for y1
		sta spritey1,x
		adc offsettable+1,y       //and second offset for y2
		sta spritey2,x
		
		lda spritex,x
		clc
		adc offsettable+2,y
		sta spritex1,x
		lda spritemsb,x
		adc #$00
		sta spritemsb1,x
		
		lda spritex,x
		clc
		adc offsettabel+3,y
		sta spritex2,x
		lda spritemsb,x
		adc #$00
		sta spritemsb2,x

This has to be looped for all sprites.

Detection

The detection is similar to the 'one size fits all' approach mentioned above. Let's assume the first slot (in spritey1, spritey2 etc.) is reserved for the player's sprite, the other slots are used for enemy sprites.

	ldx #$00
loop:	lda spritey2			
	cmp spritey1+1,x
	bcc skip		//player above enemy
		
	lda spritey2+1,x
	cmp spritey1
	bcc skip		//enemy above player
		
	lda spritex1+1,x		
	sec
	sbc spritex2
	lda spritemsb1+1,x
	sbc spritemsb2
	bcs skip		//enemy on player's left
		
	lda spritex1		//player on enemy's right?
	sec
	sbc spritex2+1,x
	lda spritemsb1
	sbc spritemsb2+1,x		
	bcc hitbysprite		//no, boxes hit each other
		
skip:	inx
	cpx #$07			
	bne loop
	rts
		
hitbysprite:
	inc $d020
	rts

Using the 2*x trick makes life easier: Delete all msb tables, use 8bit additions to figure out x1 and x2 and use comparisons instead of subtractions for collision detection.

base/sprite_collision_detection.txt · Last modified: 2015-04-17 04:33 (external edit)