This article describes Collision Detection (CD) schemes that were, are or should be implemented in SuperTux
There's a very good introduction into collision detection techniques at http://www.metanetsoftware.com/technique/tutorialA.html Make sure you've read that if you want to work on collision detection.
We're currently (July 2006) in the process of rewriting some parts of the collision detecion. Here are some random notes on how it works:
We don't do any complicated sweep tests anymore, but simply test the destination positions of objects. When pushing objects out of collisions we also mostly ignore object movement now and simply push the object out of the collision in the shortest way possible. We don't sort collisions by time anymore, but try to resolve all collisions at once. The staged approach of the old system remains though.
We do collision detection in several phases with different groups of objects with slightly different characteristics each time. Currently defined collision groups:
enum CollisionGroup {
/** Objects in DISABLED group are not tested for collisions */
COLGROUP_DISABLED,
/**
* “default” is moving object. [MovingObjects](MovingObject "wikilink") get tested against all other
* objects and against other movingobjects
*/
COLGROUP_MOVING,
/**
* a Moving object, that is not tested against other MovingObjects (or other
* MovingOnlyStatic objects), but is tested against all other objects.
*/
COLGROUP_MOVING_ONLY_STATIC,
/**
* Doesn't move and isn't explicitly checked for collisions with other
* objects (but other objects might check with this)
* The difference to COLGROUP_TOUCHABLE is that we can do multiple
* collision response tests in a row which is needed for static object
* that tux walks on. The results for collisions with STATIC objects
* are also sorted by time (so that the first hit gets handled first).
*
* Use this for static obstacles
*/
COLGROUP_STATIC,
/**
* Isn't explicitly checked for collisions with other objects. But other
* objects might check with this object.
* Difference to COLGROUP_STATIC is that collisions with this object are
* only tested once and collision response is typically not handled
*
* Use this for touchable things like spikes/areas or collectibles like
* coins
*/
COLGROUP_TOUCHABLE,
/**
* Should be used for tilemaps
*/
COLGROUP_TILEMAP
};
Current collision detection Phases:
Collisions with solid objects are handled separately before all other collisions. We use several tricks there:
TODO: Sketch the algorithm for calculating solid constraints
The following 2 cases always results in tux ending in a crushed situation. No nice solution for these cases has been proposed yet (except avoiding these situations in levels, which should be easy).
The first problem is currently worked around by relaxing the crushed condition a bit.
I'll try to describe some algorithms for collision detection. These algorithms are sweep tests, meaning that they can test for collisions along a path.
There's an example application that shows an implementation of these tests.
I just found an excelent tutorial about this collision stuff. So better go reading http://www.harveycartel.org/metanet/tutorials/tutorialA.html instead of my stuff :)
We have 2 rectangle r1 and r2, and a movement vector v that represents the relative movement of r1 to r2. The vector v has x and y component written as v.x and v.y, the rectangles have x1, y1 as their upper left point and x2, y2 as the lower right point, written as r.x1, r.y1, r.x2, r.y2.
2 rectangles collide if and only if they overlap on all axis. The trick of this algorithm is to calculate the collision separately for each axis and then combine the results to find the real collision.
The position of a point on the (first) rectangle at a give time t can be calculated with the formula p(t) = p + v * t
.
Or if we only look at the x-axis: p.x(t) = p.x + v.x * t
An intersection with the 2nd rectangle on the x axis starts to happen if p crossed the upper-left point of the 2nd rectangle. At this moment the x values of p is the same as r2.x1. We can easily calculate the time when this happens:
p.x(t) = r2.x1 <=> p.x + v.x * t = r2.x1 <=> t = (r2.x1 - p.x) / v.x
Analogue we can calculate the time when x leaves the area of the rectangle by checking for collision with r2.x2.
Now we can calculate t_min_x the time when a collision on the x-axis begins and t_max_x the time when the collision on the x-axis is over. We do the same for t_min_y and t_max_y. The 2 rectangles abviously collide when we have on overlap on both the x- and the y-axis. So if t_max_y is not smaller than t_min_x and t_max_x is not smaller than t_min_y, then the time when the 2 rectangles collide is t = max(t_min_x, t_min_y)
.
Category:Developer documentation
You can download the example application here:
http://www.stud.uni-karlsruhe.de/~uxsm/code/collplayground.tar.gz
For compilation you need to have SDL and SDL_gfx installed.
It demonstrates point-rectangle-, rectangle-rectangle-, point-polygon-, and rectangle-polygon-sweep-tests. You can set start and end-points with the left and right mouse button. With q you can change the shape we collide with from polygon to rectangle. With p you switch to point-tests, with r to rectangle tests. The startpoint is marked green, the endpoint blue and an eventual collision point white.