Collision Detection
Collision Detection is cruical to games. It can be a very complicated topic. In Galactic Armada, things will be kept super simple. We’re going to perform a basic implementation of “Axis-Aligned Bounding Box Collision Detection”:
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.1
The easiest way to check for overlap, is to check the difference bewteen their centers. If the absolute value of their x & y differences (I’ll refer to as “the absolute difference”) are BOTH smaller than the sum of their half widths, we have a collision. This collision detection is run for bullets against enemies, and enemies against the player. Here’s a visualization with bullets and enemies.
For this, we’ve created a basic function called “CheckObjectPositionDifference”. This function will help us check for overlap on the x or y axis. When the (absolute) difference between the first two values passed is greater than the third value passed, it jump’s to the label passed in the fourth parameter.
Here’s an example of how to call this function:
We have the player’s Y position in the
d
register. We’ll check it’s value against the y value of the current enemy, which we have in a variable namedwCurrentEnemyY
.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Check the y distances. Jump to 'NoCollisionWithPlayer' on failure
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ld a, [wCurrentEnemyY]
ld [wObject1Value], a
ld a, d
ld [wObject2Value], a
; Save if the minimum distance
ld a, 16
ld [wSize], a
call CheckObjectPositionDifference
ld a, [wResult]
and a
jp z, NoCollisionWithPlayer
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
When checking for collision, we’ll use that function twice. Once for the x-axis, and again for the y-axis.
NOTE: We don’t need to test the y-axis if the x-axis fails.
The source code for that function looks like this:
include "src/main/utils/constants.inc"
include "src/main/utils/hardware.inc"
SECTION "CollisionUtilsVariables", WRAM0
wResult:: db
wSize:: db
wObject1Value:: db
wObject2Value:: db
SECTION "CollisionUtils", ROM0
CheckObjectPositionDifference::
; at this point in time; e = enemy.y, b =bullet.y
ld a, [wObject1Value]
ld e, a
ld a, [wObject2Value]
ld b, a
ld a, [wSize]
ld d, a
; subtract bullet.y, (aka b) - (enemy.y+8, aka e)
; carry means e<b, means enemy.bottom is visually above bullet.y (no collision)
ld a, e
add d
cp b
; carry means no collision
jp c, CheckObjectPositionDifference_Failure
; subtract enemy.y-8 (aka e) - bullet.y (aka b)
; no carry means e>b, means enemy.top is visually below bullet.y (no collision)
ld a, e
sub d
cp b
; no carry means no collision
jp nc, CheckObjectPositionDifference_Failure
ld a, 1
ld [wResult], a
ret
CheckObjectPositionDifference_Failure:
ld a,0
ld [wResult], a
ret;