In practice
The brute force way
We can project these shapes on every axis imaginable.
If on one axis, the projections do not overlap, then there are no collisions.
Otherwise, there is a collision.
bool TestCollisionsWithSAT(const Shape& shape1, const Shape& shape2)
{
std::vector<Vector> axes = GetEveryAxisInTheWholeWorld();
for (const Vector& axis : axes)
{
Range projection1 = shape1.ProjectOnAxis(axis);
Range projection2 = shape2.ProjectOnAxis(axis);
// if there is a separating hyperplane
if (!DoRangesOverlap(projection1, projection2))
{
// then there is no collision
return false;
}
}
return true;
}
def TestCollisionsWithSAT(shape1: Shape, shape2: Shape) -> bool
axes = GetEveryAxisInTheWholeWorld()
for axis in axes:
projection1 = shape1.ProjectOnAxis(axis)
projection2 = shape2.ProjectOnAxis(axis)
# if there is a separating hyperplane
if not DoRangesOverlap(projection1, projection2):
# then there is no collision
return False
return True
Vector can be a 2D vector or a 3D vector depending on the dimension you are implementing the algorithm in.
ProjectOnAxis() can vary and be optimized depending on the implentation of Shape.
GetEveryAxisInTheWholeWorld() returns a list of every axis possibly existing (which will, of course, be a bottleneck).
The implementation of Range and DoRangesOverlap is pretty straight forward:
struct Range
{
float min, max;
};
bool DoRangesOverlap(const Range& range1, const Range& range2)
{
return range1.max > range2.min && range2.max > range1.min;
}
class Range():
min = 0
max = 0
def DoRangesOverlap(range1: Range, range2: Range) -> bool:
return range1.max > range2.min and range2.max > range1.min
public struct Range
{
public float min;
public float max;
public static bool DoRangesOverlap(Range range1, Range range2)
{
return range1.max > range2.min && range2.max > range1.min;
}
};
public class Range
{
public float min;
public float max;
public static bool DoRangesOverlap(Range range1, Range range2)
{
return range1.max > range2.min && range2.max > range1.min;
}
};
The smarter way
GetEveryAxisInTheWholeWorld() will, of course, make the algorithm too slow to be used.
However, we actually don’t have to check every axis.
ProjectOnAxis() can also be optimized.
More informations on that in the next chapters.