Collision Code Snippet Resource
- Intro
Pretty much every week, theres at least 1 (usually more) question regarding getting collision working in games. Its usually one of the first questions newcommers have, but usually the last to get answered. So, in hopes of lightening the load of these questions and providing a quick way for people to show newcommers all of the collision snippets on the TGC forums, Ive made this thread.
Below is a compilation of all of the usefull code snippets, dlls, links to other sites/resources, and anything else that I could find to do with collision, hope it helps.
---o
Sparky's Collision Dll (FREE)
---o
Nuclear Glory Collision ($)
---o
Kensupen's BSP Style Sliding Collision Snippet
---o
G-Man/Lost In Thought's Sliding Collision Snippet
---o
TDK's DB Collision Made Simple Tutorial
---o
RUCCUS' Collision Function (easy to implement)
---o DBP Native Collision Commands Example:
`Setup the game
SYNC ON:SYNC RATE 0:AUTOCAM OFF:HIDE MOUSE
`Make a player object
MAKE OBJECT CUBE 1,10
SET OBJECT COLLISION ON 1
`Make a matrix, its only for a visual aspect, and doesnt effect collision at all.
MAKE MATRIX 1,1000,1000,10,10
POSITION MATRIX 1,-500,0,-500
`Make an object to collide with
MAKE OBJECT BOX 2,100,200,300
POSITION OBJECT 2,200,0,500
SET OBJECT COLLISION ON 2
`Setup the camera
POSITION CAMERA 0,200,-500
`Main loop
DO
`Store the object's old position, so we can move them
`back to it if we detect a collision
ox# = OBJECT POSITION X(1)
oy# = OBJECT POSITION Y(1)
oz# = OBJECT POSITION Z(1)
`Handle object movement
MOVE OBJECT 1, (UPKEY()-DOWNKEY())*0.5
TURN OBJECT LEFT 1, (LEFTKEY()-RIGHTKEY())*0.5
`Check for a collision between object 1 AND 2
`If a collision occurs, position object 1 back at it's old coordinates.
`The OBJECT COLLISION() command takes 2 parameters,they represent the 2 objects
`you want to detect collision with.
`Providing 0 as the second number in the command will result in a check for collision
`with all of the objects in the world, returning a 1 on any collision detection.
IF OBJECT COLLISION(1,2) THEN POSITION OBJECT 1, ox#,oy#,oz#
`Refresh the screen
SYNC
`Repeat
LOOP
---o Matrix Collision Using the Get Ground Height() command
(easily adapted to Advanced Terrain by using the Get Terrain Height() command instead.
`Setup the game
SYNC ON:SYNC RATE 0:AUTOCAM OFF:HIDE MOUSE
`Make a player object
MAKE OBJECT CUBE 1,10
POSITION OBJECT 1,500,0,0
`Make a matrix, its only for a visual aspect, and doesnt effect collision at all.
FOR x = 1 TO 10
FOR y = 1 TO 10
DOT x,y,RGB(000,RND(255),000)
NEXT y
NEXT x
GET IMAGE 1,1,1,10,10
MAKE MATRIX 1,1000,1000,10,10
PREPARE MATRIX TEXTURE 1,1,10,10
POSITION MATRIX 1,0,0,0
RANDOMIZE MATRIX 1,60
UPDATE MATRIX 1
`Setup the camera
POSITION CAMERA 500,200,-500
`Main loop
DO
`Handle object movement
MOVE OBJECT 1, (UPKEY()-DOWNKEY())*0.5
TURN OBJECT LEFT 1, (LEFTKEY()-RIGHTKEY())*0.5
`Store the object's current X and Z position.
x# = OBJECT POSITION X(1)
z# = OBJECT POSITION Z(1)
`Now we calculate the y position of object 1. We do this by using the GET GROUND HEIGHT() command.
`This command has 3 parameters; the first is the matrix number of the matrix you want to find the height of,
`the second/third is the x#/y# location in the world that you want to find the height of the tile located there.
`Basically, we provide the command with our player's x and z location, and it returns the y location the player
`should be at to be walking ontop of the matrix.
`Also, we add to this number half of the object's height. This way, the exact bottom of the player's cube will stay
`directly on the surface of the matrix, instead of the centre of the object being on the surface, which would look weird.
y# = (OBJECT SIZE Y(1)/2) + GET GROUND HEIGHT(1,x#,z#)
`Finally, position the object at it's newly calculated y location.
POSITION OBJECT 1, x#,y#,z#
`Refresh the screen
SYNC
`Repeat
LOOP
---o Raycasting using DBP's Internal Intersect Object() command.
`Setup the game
SYNC ON:SYNC RATE 0:AUTOCAM OFF:HIDE MOUSE
`Make a player object
MAKE OBJECT CUBE 1,10
`Make a matrix
MAKE MATRIX 1,1000,1000,10,10
POSITION MATRIX 1,-500,0,-500
`Make a box to detect collision with
MAKE OBJECT BOX 2,100,200,300
POSITION OBJECT 2,200,0,500
`Orient the camera
POSITION CAMERA 0,100,-500
DO
`Ray casting is pretty simple. Basically, think of it as a laser. This laset gets sent out from a starting point,
`towards an ending point. If the ray hit's any polygons (faces) of the model being checked against, the ray bounces back,
`returning the distance from the starting point to the collision (or "intersection").
`How do you use it for collision detection?
`Well, you store the player's old coordinates (the starting position of the ray) and the player's
`new coordinates after theyve moved/gravity has taken place/anything else that will move the player, which
`gives us the ray's destination coordinates.
`Now that we have the coordinates, we use the INTERSECT OBJECT command, to check if an object's polygons are
`inbetween the 2 coordinates. If so, the player must have ran into the object, and thus so we can position the player
`back at their old coordinates (or make them slide or bounce or die, whatever).
`Store the object's old coordinates
ox# = OBJECT POSITION X(1)
oy# = OBJECT POSITION Y(1)
oz# = OBJECT POSITION Z(1)
`Handle object movement
MOVE OBJECT 1, (UPKEY()-DOWNKEY())*0.5
TURN OBJECT LEFT 1, (LEFTKEY()-RIGHTKEY())*0.5
`Store the object's new coordinates
nx# = OBJECT POSITION X(1)
ny# = OBJECT POSITION Y(1)
nz# = OBJECT POSITION Z(1)
`Find the collision distance to Object 2 using our stored variables.
collisionDistance# = INTERSECT OBJECT(2, ox#,oy#,oz#,nx#,ny#,nz#)
`If the collision distance returned is greater than 0 then a collision must have occured, so we reposition
`the object at it's old coordinates.
IF collisionDistance#
POSITION OBJECT 1, ox#,oy#,oz#
ENDIF
`Refresh the screen
SYNC
`Repeat
LOOP
---o Camera Collision in Third Person View:
`App setup
SYNC ON:SYNC RATE 0:AUTOCAM OFF:HIDE MOUSE
`Make a matrix, purely for visual purposes
MAKE MATRIX 1,1000,1000,10,10
`Make our player object
MAKE OBJECT CUBE 1,10
`Make an object our camera can collide with
MAKE OBJECT BOX 2,100,100,10
POSITION OBJECT 2,0,50,100
`This variable represents the distance the camera will maintain
`infront of any polygons it sees between it and the player
wallDist# = 5
`Main loop
DO
`Object movement
MOVE OBJECT 1, (UPKEY()-DOWNKEY())*0.5
YROTATE OBJECT 1, WRAPVALUE(OBJECT ANGLE Y(1) + ((RIGHTKEY()-LEFTKEY())*0.5))
`Store the object's position
x# = OBJECT POSITION X(1)
y# = OBJECT POSITION Y(1)
z# = OBJECT POSITION Z(1)
`Store the object's y angle, for third person camera
angle# = OBJECT ANGLE Y(1)
`Third person cam code
POSITION CAMERA x#,y#+20,z#
YROTATE CAMERA angle#
MOVE CAMERA -100
`Store the cam's position
cx# = CAMERA POSITION X()
cy# = CAMERA POSITION Y()
cz# = CAMERA POSITION Z()
`Check if there are any polygons of object 2 inbetween the
`player and the camera.
colDist# = INTERSECT OBJECT(2,cx#,cy#,cz#,x#,y#,z#)
`If there are any polygons, move the camera forward by
`the distance from the camera to the intersection plus
`the wall distance variable.
IF colDist#
MOVE CAMERA colDist# + wallDist#
ENDIF
`Refresh the screen
SYNC
`Repeat
LOOP
I threw together this code to give a better idea of the kind of FPS rates each method of collision gives you. It starts out using Sparky's dll. Pressing 2 will switch to DB Intersect Object, pressing 3 to DB Polygon Collision, 1 back to Sparky's, and 0 if you'd like to turn off collision all together.
My results (the FPS at the time of a collision occuring)
Sparkys Dll: 345 FPS
DB Intersect Object: 335 FPS
DB Polygon Collision: 270 FPS
Here's the code;
`Sliding Collision with Sparky's Collision dll
`By RUCCUS
`----------
`Email/MSN: Ask-RUCCUS@hotmail.com
`Main Program Settings
SYNC ON
SYNC RATE 0
AUTOCAM OFF
`Make a simple matrix, purely visual, not needed.
MAKE MATRIX 1,1000,1000,10,10
POSITION MATRIX 1,-500,0,-500
`Make the user's object.
MAKE OBJECT CUBE 1,20
POSITION OBJECT 1,0,5,-500
`Make a box object, replace this with your map.
MAKE OBJECT SPHERE 2,200,32,32
POSITION OBJECT 2,0,25,60
`Setup object 2 in group 0
SC_SetupObject 2,0,0
`Position/orient the camera.
POSITION CAMERA 0,100,-600
POINT CAMERA 0,0,0
collisionMode = 1
`Start the main program loop.
DO
`Check for collision mode
IF KEYSTATE(11) THEN collisionMode = 0
IF KEYSTATE(2) THEN collisionMode = 1
IF KEYSTATE(3) THEN collisionMode = 2
IF KEYSTATE(4) THEN collisionMode = 3
`Store the user's old position on the xyz axis
OX# = OBJECT POSITION X(1)
OY# = OBJECT POSITION Y(1)
OZ# = OBJECT POSITION Z(1)
`Handle the player movement/orientation
MOVE OBJECT 1,( UPKEY()-DOWNKEY() ) * .5
TURN OBJECT LEFT 1,( LEFTKEY()-RIGHTKEY() ) * .5
IF collisionMode = 1
`collisionMode 1 uses Sparky's Collision dll
`Store the player's new position on the xyz axis, after they've moved.
X# = OBJECT POSITION X(1)
Y# = OBJECT POSITION Y(1)
Z# = OBJECT POSITION Z(1)
`Check for collision
collisionDist# = SC_raycast(2,OX#,OY#,OZ#,X#,Y#,Z#,0)
IF collisionDist#
POSITION OBJECT 1, OX#, OY#, OZ#
ENDIF
ENDIF
IF collisionMode = 2
`collisionMode 2 uses DBP's raycasting
`Store the player's new position on the xyz axis, after they've moved.
X# = OBJECT POSITION X(1)
Y# = OBJECT POSITION Y(1)
Z# = OBJECT POSITION Z(1)
`Check for collision
collisionDist# = INTERSECT OBJECT(2,OX#,OY#,OZ#,X#,Y#,Z#)
IF collisionDist#
POSITION OBJECT 1, OX#, OY#, OZ#
ENDIF
ENDIF
IF collisionMode = 3
`collisionMode 3 uses DBP's internal polygon collision
SET OBJECT COLLISION ON 1
SET OBJECT COLLISION ON 2
SET OBJECT COLLISION TO SPHERES 1
SET OBJECT COLLISION TO POLYGONS 2
IF OBJECT COLLISION(1,0) THEN POSITION OBJECT 1,OX#,OY#,OZ#
ElSE
`This just stops the computer from checking for polygonal collisions
`if the mode isnt set to 3.
SET OBJECT COLLISION OFF 1
SET OBJECT COLLISION OFF 2
ENDIF
TEXT 0,0,"FPS: "+STR$(SCREEN FPS())
TEXT 0,15,"Press 1 For Sparkys dll | 2 for DBP's raycasting | 3 for DBP's polygonal collision detection | 0 for no collision"
TEXT 0,30,"Current Collision Mode: "+STR$(collisionMode)
`Refresh the screen
SYNC
`Repeat
LOOP
`This is needed for sparky's dll to work
DELETE MEMBLOCK 1
Just a note, the difference between Sparky's dll and the DB Intersect Object command's FPSs might not seem too large now, but if you use multiple objects to check collision against, or use an object with a larger polygon count, you'll see where Sparky's dll truly shines. Feel free to put in a map in place of the sphere there.
Make your collision faster/smarter: This is a method used in tonnes of games out there, even the console games. To make your collision responses faster and less probable of a buggy collision occuring, make collision maps. Collision maps are basically a second, extremely low poly, untextured version of your main map, that's hidden in your game world. You then detect collision with this collision map instead of your main map. Not only does this method tend to increase FPS drastically, but as I said above, it allows you to make your collision responses more predictable. By this I mean, if you had an extremely irregular shaped object, or a small object floating in the air, or a bunch of cracks in the cement of a city model, your player *might* get positioned weirdly depending on how you're handling collision. If you're trying to squeeze out more fps from your game, make a collision map, in the past it's increased my FPS more than 300 percent.
Breaking up the Workload: Another great tip is to cut your map up into smaller grid sections. Then, only detect collision with the closest grid section to the user. If you have a 100000 polygon map (not uncommon), and divided it up into just 10 grid pieces, you would reduce the amount of polygons being checked for intersection in your world down to just 10000. Thats a 90000 polygon difference! Believe me, it makes all the difference.
Dont check if you dont have to: If your player is skydiving out of a plane attempting to land into the main mission area for their next objective, are they going to be running into anything in the air? If your player's not moving, and nothing else is moving that could move them, are they going to ever hit anything? Chances are they wont, so why bother detecting for collision at those times? Another huge FPS increase.
Bullet Calculations:: When most users start out making their first FPS, they automatically assume they need to make tonnes of bullet objects when the user fires their gun. But in reality, as long as the gun being fired is fairly modern, chances are it'll be shooting bullets so fast that all you'll see is the bullet spray. Why make the bullet objects then? Instead, send an intersection check going from the player's gun to a point infront of the player's gun far away, if you detect an intersection with an enemy, decrease their health. This is what all proffessional games do. How do they get the bullet spray effect? Plains or spheres, depending on the effect. Usually a plain is positioned between the player's gun and where the bullet hits, and is stretched to fit between the 2 points. The plain is then textured with a transparent gunspray image, and hidden/shown repeatedly. The same effect can be achieved with using a sphere with an image of gunspray on it, examples of using spheres can be found in the free game "America's Army".
Bullet Decals: For this one you'll want to use Sparky's dll. If you look in sparky's helpful example programs, you'll see one where he constantly positions a plain on the object being clicked on with the mouse, and he orients this plain to face the same direction as the polygon hit. Thats a perfect decal system right there; just change the code to leave the decals when the user fires a bullet, and have them fade after a time period. Instant bullet holes.
- Other Useful Links
Overview of 3D Collision
- Outro
Thats all for now, feel free to post with links to informative sites, other code snippets, plugins, or theories on collision detection that I may have missed, and Ill add them to the list if I think they fit the shoe.
- RUC'