Game Development Community

dev|Pro Game Development Curriculum

Collision Tutorial Object

by Matt Fairfax · 03/28/2004 (6:20 am) · 14 comments

Download Code File

Basic break down of collision in TGE:

The moving objects in TGE like the player, vehicle, or item initiate the collisions. At some point in
their processTick() or in a function that is called by processTick() they will make a call to the scenegraph
to update their working collision set. This is done by calling the Convex::updateWorkingList() function.
You hand a Box3F that encompasses the area of everything you want to collide with (generally includes a
projected/predicted bounding box with the current velocity accounted for) and a collision mask that allows
you to specify what ObjectTypes you want to collide against.

This functions loops through all of the objects in the same bin (read Melv's description of bins -
www.garagegames.com/index.php?sec=mg&mod=resource&page=view&qid=3217) and checks to see if their
bounding boxes overlap and if they are have the proper ObjectType. If their bounding boxes overlap
then buildConvex() is called for each object.

Inside buildConvex() is where each SceneObject decides how to represent themselves to the rest of the
objects. In order for collision to occur against an object it must register at least one convex with
the working list of the convex that is passed in. Once this convex is registered all of the rest of the
collision code acts against it and never directly against the original sceneobject. A convex itself doesn't
store any vertex/edge/face information and really can't ever return any meaningful collision information,
which is why you almost always see a subclass of Convex created for each sceneobject (InteriorConvex,
ShapeBaseConvex, TerrainConvex, etc.)

These subclasses use a pointer back to the original sceneobject (Convex::mObject or a separate pointer
in the subclass) to pull meaningful collision information for the functions getPolyList(), support(),
and getFeatures(). They also often include a unique id that allows them to pull only a subset of the
information from the original. For example, InteriorConvex::hullId allows getPolyList() to only pull
the polys for a specific hull instead of *all* the polys in the interior. Most objects are going to be
complex enough to require more than one convex to represent it. It is also beneficial to be able to split
up the object into smaller convexes simply so that the collider doesn't have to collide against
too many unrelated polys (like those on the other side of an interior). There is a point of diminishing
return though where you lose speed from having too many convexes as opposed to testing against too many
unrelated polys. I found for practical purposes, going smaller/fine-grained than about half the size
of the player object was actually slower.

Once the scene has been traversed and all of the relavent convexes have been registered with the working
list for our collider, it is time for it to do some actual collisions. Players use the Convex::getPolyList()
in Player::updatePos() to generate a CollisionList. A CollisionList is simply an array of Collision
struct. The Collision struct includes information like Point3F point (the point where a collision occurs),
VectorF normal (the normal of the collision). Also for a player collision values are set for U32 face (which
face was hit) and F32 faceDot (-dot product of face with poly normal). These values are used in various
physics calculations that are added into the players velocity (for example: running straight into a wall
brings the forward velocity to zero). Most other movable objects in TGE (like Item) use a similar approach.

However, the Vehicles use a completely different collision scheme. They use Convex::getCollisionInfo()
which uses a transform matrix, a scale, and a tolerance in order to return a CollisionLlist that the
vehicles use to generate forces that effect its velocity. Convex::getCollisionInfo() makes use of
Convex::support() and Convex::getFeatures() in order to do this.

Why the difference from the player's use of Convex::getPolyList()? It boils down to the fact that the
player never tilts or leans so it can use an optimized collision scheme whereas the vehicles are often
oriented to the terrain or the interior or shape or whatever it is sitting on. Thus, it needs a bit
more complex and robust collision test (basically per poly with some optimizations in place given the
closed convex nature of the collision test). The player collision is a lot less picky about the convexity
of the collision data. The vehicle collision requires not only convexity but the collision faces *must*
form a *closed* convex in order for it to work correctly.

Ok, so enough theory. All you really want to know is what you need to implement to make collisions work
correctly, right? Here are the functions you need to override for your convex (see the code for more
specifics):

SceneObject::buildConvex() - this is where your SceneObject gets the chance to tell a collider about itself.
At a minimum you should submit one convex with mObject (a pointer to the SceneObject that this convex belongs
to). If the convex tracks its bounds separately (the bounds doesn't match the SceneObject's bounds) or if the
convex has an id (in case there is more than one) then you need to fill these out at this point also.

SceneObject::castRay() - this is only indirectly related to collision. It is primarily used for projectile
collisions, wheel collisions, and camera collisions (when in 3rd person). You are given a start point and an
end point. You use these to fill in an info struct with t (the distance/time along the line defined by start
and end with 0.0f being start and 1.0f being end that a collision occurs), normal (the normal of the collision),
and object (a pointer to the SceneObject).

Convex::getPolyList() - this is the biggy for player collisions. You are given a pointer to a AbstractPolyList to
add polys to. Basically, just add any polys encompassed by your convex. Don't forget to transform the box from
world space into your object space for testing. These faces are not limited to 3 points (triangle) but all
of the points submitted for each face must lie on the face plane.

Convex::support() - this is a pretty simple function. Simply return the furthest point from the point handed in.
Easiest way to do this is to loop through all the points and return the one where the dot product is the
greatest.

Convex::getFeatures() - you are handed in a transform matrix, a normal, and a pointer to a ConvexFeature structure
to fill out. You add all of the points (transformed), faces (transform the normals), and edges of your convex object
to the ConvexFeature structure. These faces can only be triangles and they *must* define a closed convex shape.
These are used for vertex-to-face and edge-to-edge collisions later.

Convex::getBoundingBox() - this is called to the bounding box for this convex.

Well, that is TGE collision in a nut shell. If you poke through the various Convex subclasses you can see
decent examples of how to implement all of this. BoxConvex was particularily helpful to me when I was getting
started though it has some optimizations that make it hard to read in places. Hopefully my included code will
be a little easier to read.

About the author

I am a Game Designer at PopCap who has worked on PvZ Adventures, PvZ2, Peggle Blast, and Bejeweled Skies. I am an ex-GarageGames employee who helped ship TGE, TGEA, Torque 3D, and Constructor.


#1
03/28/2004 (9:36 pm)
The download is currently not working :(
#2
03/29/2004 (2:39 am)
Thank you! I'm sure this will come in handy just as much as Melvs fxRenderObject :D

Its still not working though :(
#3
03/29/2004 (6:14 am)
Odd...maybe the edit borked it

I just reuploaded the file and it appears to be working now
#4
04/01/2004 (10:54 pm)
You rock :)
#5
07/02/2004 (4:03 am)
Thanks Matthew, this resource has no doubt saved me from weeks of head scratching frusturation :)
#6
12/17/2005 (7:24 am)
i also have a broken download file here..
it actually is downloading, but the file seems damaged and winzip cant open it.
oh, can this be fixed?
greetings
ka
www.3dtowns.at
#7
01/03/2007 (12:14 am)
thnaks Matthew, great resource!
#8
02/05/2007 (11:10 pm)
I have a question on the TutCollisionSimple::buildConvex() method.

The buildConvex() method in shapebase keeps a list (mConvexList) of all convex objects created in buildConvex. It seems to use this list to delete old convex objects that are created in buildConvex() but no longer referenced.

Why isn't this functionality necessary for TutCollisionSimple?

Thanks
Todd
#9
03/30/2007 (10:11 pm)
Has anyone got collision actually working in the RTS environment?

If so please do let me know, with the working source code!
#10
01/03/2008 (10:20 am)
One of the best explanation of the engine internals iv seen. greate job.!!!!!
#11
05/26/2008 (6:27 pm)
Great resource, no matter the age. Helped me understand player collisions greatly, thankyou.
#12
02/10/2010 (6:55 pm)
This is fantastic! We need many more tutorials like this one.
#13
02/27/2013 (12:33 pm)
Sorry for this huge bump, but the download link to the code File is broken. Does anybody have it?
#14
04/12/2013 (3:19 pm)
I was researching some collision stuff and re found this thread and remembered I did a website dump of GG just before the whole InstantAction thing in case the website went dark.

So here is a link to the file I saved.