Basic collision
Methods to check if two shapes overlap, for different combinations of shapes. This kind of checks is normally used to check if two objects collide with each other.
- On fixed point
- 2D collision
- 3D collision
- More complex shapes
On fixed point
The article about speed physics tells you to use fixed point values to improve accuracy. However, you'd be dealing with 32-bit values which for some of these checks could become a pain to cope with.
Collision can afford to be more coarse. If you just take the integer part, you may get away with 16-bit numbers, which will make this a lot simpler (when working in assembly) and faster (in general). If you're using 1px = 65536 as suggested in the article, then it means the first word of the number will be the integer half which you can read as-is (avoiding even the bit shifting).
Point vs. box
The simplest type of collision is to check if a point is inside a box (e.g. rectangle or square). This is useful when trying to point at something, or for checks against small things (like a bullet).
To achieve this we need to do a range check (i.e. check if a value is within a given range) to both X and Y axes, with the range being the box boundaries. A range check is pretty simple, just compare the value against the minimum and maximum boundaries of the range, if it's between them then the value is inside:
(x ≥ min) and (x ≤ max)
Do this to both axes and you have a way to check if a point is inside a box (if both range checks success then the point is inside the box):
if (point_x >= box_x1) and
(point_x <= box_x2) and
(point_y >= box_y1) and
(point_y <= box_y2)
then
...
end
Box vs. box
A more common type of check however is box against a box. Most (or all) objects in a game will have a "collision box", which is referring to this. It's not really harder than point against a box but may be a bit trickier to understand.
In this case what we need is to check if two ranges overlap instead. It looks like below, the idea is to ensure that the minimum of one range doesn't go past the maximum of the other range (and vice versa):
(1st range min ≤ 2nd range max) and (1st range max ≥ 2nd range min)
Now take it to both axes and you get a box vs. box collision check:
if (box1_x1 <= box2_x2) and
(box1_x2 >= box2_x1) and
(box1_y1 <= box2_y2) and
(box1_y2 >= box2_y1)
then
...
end
Point vs. circle
Sometimes you have an object that's more circlar than rectangular (and large enough for the difference to stick out). In this case, if may be more appropriate to check against a circular shape.
To check if a point is within a circle, you need to know the distance between the point and the circle's center. If the distance is within the radius of the circle, then the point is inside.
To get the distance we need to use Pythagoras' theorem:
distance2 = X difference2 + Y difference2
If you wanted the actual distance you'd need a square root, but since we just need to compare against it, we can avoid the square root and compare the squared values directly. Then only the multiplications are left, but as long as the values are 16-bit it's not a big deal for the 68000 (note: the 68000 will produce a 32-bit result, so don't worry about numbers becoming too big either).
Putting all together, it looks something like this:
delta_x = circle_x - point_x
delta_y = circle_y - point_y
limit = circle_radius
if (delta_x * delta_x) +
(delta_y * delta_y) <= (limit * limit)
then
...
end
Circle vs. circle
Again, rather than point against a circle it may be more useful to check between two circles (e.g. two balls colliding). The idea here is similar, so refer to that to understand what's going on.
To check if two circles overlap you need to compare the distance between their centers. If you add up the radius of both and the distance is under that, it means the two circles are overlapping (i.e. collision).
delta_x = circle2_x - circle1_x
delta_y = circle2_y - circle1_y
limit = circle2_radius + circle1_radius
if (delta_x * delta_x) +
(delta_y * delta_y) <= (limit * limit)
then
...
end
Iwis says
Remember you can cheat. For example, if your player (a relatively small object) is normally a box but you need collision against a large circular object, you can probably get away with treating the player as a circle for this particular case. Same goes for other shapes.
3D point vs. box
Working in 3D? (maybe an isometric game?) Then you're going to need to extend collision checks to work in three dimensions too.
This one is an extension to the 2D point against box check. The only difference is that we throw in the Z axis as an additional check, otherwise it works the same way.
if (point_x >= box_x1) and
(point_x <= box_x2) and
(point_y >= box_y1) and
(point_y <= box_y2) and
(point_z >= box_z1) and
(point_z <= box_z2)
then
...
end
3D box vs. box
Extending the box against box check to 3D works the same way as for the previous case: add one more range overlap check for the Z axis, otherwise works the same way.
if (box1_x1 <= box2_x2) and
(box1_x2 >= box2_x1) and
(box1_y1 <= box2_y2) and
(box1_y2 >= box2_y1) and
(box1_z1 <= box2_z2) and
(box1_z2 >= box2_z1)
then
...
end
Point vs. sphere
The 3D equivalent to point against circles is point against spheres. If you understood that one, then this one is easy: throw in the Z axis into the additions as well and now you have a point against spheres check.
delta_x = sphere_x - point_x
delta_y = sphere_y - point_y
delta_z = sphere_z - point_z
limit = sphere_radius
if (delta_x * delta_x) +
(delta_y * delta_y) +
(delta_z * delta_z) <= (limit * limit)
then
...
end
Sphere vs. sphere
The 3D equivalent to circles against circles is spheres against spheres. As with point against sphere, it pretty much involves including the Z axis in the addition.
delta_x = sphere2_x - sphere1_x
delta_y = sphere2_y - sphere1_y
delta_z = sphere2_z - sphere1_z
limit = sphere2_radius + sphere1_radius
if (delta_x * delta_x) +
(delta_y * delta_y) +
(delta_z * delta_z) <= (limit * limit)
then
...
end
Point vs. cylinder
Another useful shape in 3D is cylinders. A check between cylinders is like a mix of a circle check for two of the axes and box check for the remaining axis.
This is an example that should give an idea. The cylinder shape checked for is upright, so the "box" check goes to the Z axis, but it can be applied to either of the three axes.
delta_x = cylinder_x - cylinder_x
delta_y = cylinder_y - cylinder_y
limit = cylinder_radius
if (point_z >= cylinder_z1) and
(point_z <= cylinder_z2) and
((delta_x * delta_x) + (delta_y * delta_y) <= (limit * limit))
then
...
end
Cylinder vs. cylinder
This is the cylinder equivalent of box against box or circle against circle. Like point against cylinder, the idea is to do a circle check for two of the axes and a box check for the remaining axis.
delta_x = cylinder2_x - cylinder1_x
delta_y = cylinder2_y - cylinder1_y
limit = cylinder2_radius + cylinder1_radius
if (cylinder1_z1 >= cylinder1_z2) and
(cylinder1_z2 <= cylinder1_z1) and
((delta_x * delta_x) + (delta_y * delta_y) <= (limit * limit))
then
...
end
More complex shapes
Some objects may have more complex shapes where these simpler ones would stick out pretty badly. In these cases, you could try doing multiple checks against them. For example, a large L-shaped object could be handled as two boxes.