Enemy-Bullet Collision
When we are udating enemies, we’ll call a function called “CheckCurrentEnemyAgainstBullets”. This will check the current enemy against all active bullets.
This fuction needs to loop through the bullet object pool, and check if our current enemy overlaps any bullet on both the x and y axis. If so, we’ll deactivate the enemy and bullet.
Our “CheckCurrentEnemyAgainstBullets” function starts off in a manner similar to how we updated enemies & bullets.
This function expects “hl” points to the curent enemy. We’ll save that in a variable for later usage.
include "src/main/utils/hardware.inc"
include "src/main/utils/constants.inc"
include "src/main/utils/hardware.inc"
SECTION "EnemyBulletCollisionVariables", WRAM0
wEnemyBulletCollisionCounter: db
wBulletAddresses: dw
SECTION "EnemyBulletCollision", ROM0
; called from enemies.asm
CheckCurrentEnemyAgainstBullets::
ld a, l
ld [wUpdateEnemiesCurrentEnemyAddress], a
ld a, h
ld [wUpdateEnemiesCurrentEnemyAddress+1], a
xor a
ld [wEnemyBulletCollisionCounter], a
; Copy our bullets address into wBulletAddress
ld a, LOW(wBullets)
ld l, a
ld a, HIGH(wBullets)
ld h, a
jp CheckCurrentEnemyAgainstBullets_PerBullet
As we loop through the bullets, we need to make sure we only check active bullets. Inactive bullets will be skipped.
CheckCurrentEnemyAgainstBullets_PerBullet:
ld a, [hl]
cp 1
jp nz, CheckCurrentEnemyAgainstBullets_Loop
First, we need to check if the current enemy and current bullet are overlapping on the x axis. We’ll get the enemy’s x position in e, and the bullet’s x position in b. From there, we’ll again call our “CheckObjectPositionDifference” function. If it returns a failure (wResult=0), we’ll start with the next bullet.
We add an offset to the x coordinates so they measure from their centers. That offset is half it’s respective object’s width.
CheckCurrentEnemyAgainstBullets_Check_X_Overlap:
; Save our first byte address
push hl
inc hl
; Get our x position
ld a, [hli]
add 4
ld b, a
push hl
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Start: Checking the absolute difference
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The first value
ld a, b
ld [wObject1Value], a
; The second value
ld a, [wCurrentEnemyX]
add 8
ld [wObject2Value], a
; Save if the minimum distance
ld a, 12
ld [wSize], a
call CheckObjectPositionDifference
ld a, [wResult]
and a
jp z, CheckCurrentEnemyAgainstBullets_Check_X_Overlap_Fail
pop hl
jp CheckCurrentEnemyAgainstBullets_PerBullet_Y_Overlap
CheckCurrentEnemyAgainstBullets_Check_X_Overlap_Fail:
pop hl
pop hl
jp CheckCurrentEnemyAgainstBullets_Loop
Next we restore our hl variable so we can get the y position of our current bullet. Once we have that y position, we’ll get the current enemy’s y position and check for an overlap on the y axis. If no overlap is found, we’ll loop to the next bullet. Otherwise, we have a collision.
CheckCurrentEnemyAgainstBullets_PerBullet_Y_Overlap:
; get our bullet 16-bit y position
ld a, [hli]
ld b, a
ld a, [hli]
ld c, a
; Descale our 16 bit y position
srl c
rr b
srl c
rr b
srl c
rr b
srl c
rr b
; preserve our first byte addresss
pop hl
push hl
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Start: Checking the absolute difference
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; The first value
ld a, b
ld [wObject1Value], a
; The second value
ld a, [wCurrentEnemyY]
ld [wObject2Value], a
; Save if the minimum distance
ld a, 16
ld [wSize], a
call CheckObjectPositionDifference
pop hl
ld a, [wResult]
and a
jp z, CheckCurrentEnemyAgainstBullets_Loop
jp CheckCurrentEnemyAgainstBullets_PerBullet_Collision
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; End: Checking the absolute difference
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
If a collision was detected (overlap on x and y axis), we’ll set the current active byte for that bullet to 0. Also , we’ll set the active byte for the current enemy to zero. Before we end the function, we’ll increase and redraw the score, and decrease how many bullets & enemies we have by one.
CheckCurrentEnemyAgainstBullets_PerBullet_Collision:
; set the active byte and x value to 0 for bullets
xor a
ld [hli], a
ld [hl], a
ld a, [wUpdateEnemiesCurrentEnemyAddress+0]
ld l, a
ld a, [wUpdateEnemiesCurrentEnemyAddress+1]
ld h, a
; set the active byte and x value to 0 for enemies
xor a
ld [hli], a
ld [hl], a
call IncreaseScore
call DrawScore
; Decrease how many active enemies their are
ld a, [wActiveEnemyCounter]
dec a
ld [wActiveEnemyCounter], a
; Decrease how many active bullets their are
ld a, [wActiveBulletCounter]
dec a
ld [wActiveBulletCounter], a
ret
If no collision happened, we’ll continue our loop through the enemy bullets. When we’ve checked all the bullets, we’ll end the function.
CheckCurrentEnemyAgainstBullets_Loop:
; increase our counter
ld a, [wEnemyBulletCollisionCounter]
inc a
ld [wEnemyBulletCollisionCounter], a
; Stop if we've checked all bullets
cp MAX_BULLET_COUNT
ret nc
; Increase the data our address is pointing to
ld a, l
add PER_BULLET_BYTES_COUNT
ld l, a
ld a, h
adc 0
ld h, a