Rigid Shape Class
by Thomas \"Man of Ice\" Lund · 04/07/2004 (9:57 am) · 256 comments
Download Code File
History
2005-09-08 Updated with performance fix from XoCluTch
What is this?
For my game I needed a boulder that rolls down a hill, and that one needs to evade. Initial attempts to use the existing classes (items, shapes and especially projectiles) fail because of too simple physics and/or lack of collision box support. I was faced with either implementing collision boxes in the projectile class, look into ODE or try to code my own rigid body class.
Thanks to Ben Garney I didnt have to do any of these (thanks ;-) ), as there already exists rigid physics in the engine. The rigid.cc/h files have everything needed, but they are only available as con/net objects using the vehicle classes.
So I simply took the base vehicle class and the hover vehicle class, merged them together and removed most of the unneeded code. The result is actually fantastic, and I cant believe this isnt standard part of Torque.
As the code basically is a hover vehicle there might be parts of the code that should be removed further. If you spot any of those, then post here and I'll update the codebase.
What does it look like?
No resource without a movie :-)
Here is the final result from a tech demo level in my upcomming action adventure game.
www.codejar.com/rigidshape4.wmv
I also did a few early tests and I've included the movies here. The lack of realism is totally due to way too much impulse applied with a large vertical factor + low mass for the chests.
www.codejar.com/rigidshape.wmv
www.codejar.com/rigidshape2.wmv
www.codejar.com/rigidshape3.wmv
All movies are approx 3 MB
How to add
First thing is to add the 2 attached files in the zip to your engine\game dir and to your project. Then open the shapebase.h and find this
and add
Also in the same file down the bottom find this
and add
Recompile your engine and thats it.
If you want to do this "for real", then one also needs to define a new objectType. I have reused the ShapeBaseObjectType - change that if you want or go through tons of code and add a RigidShapeObjectType.
How to use
From script you now got access to a RigidShapeData datablock and a RigidShape object type. Your DTS object is required to have a mass node, but nothing else. The code still includes dusttrail and splash emitters from the vehicle code, as well as impact + water sound. This example does not use any of those.
An example datablock for a rigid shape is included below
By including the category="" it now shows up in the world editor under the Shapes, and its fully working. Spawn the object on a hilltop and see it roll down :-)
For the mission editor to work you will need to add a create() function that hooks into the mission editor. You can either put this into a rigidShape.cs file (dont forget to load it from game.cs) or put it into any .cs file in the server\script
If you want to have a little fun pushing things around then add this to your player onCollision:
I've done a few tests with forces, masses and such - and as you saw from my movies with varying results.
The objects are fully network aware, and I bet this code can replace ODE for most purposes if you dont need total realism.
As I wrote earlier, the code can be stripped down further. There are various pieces of the physics that I do not understand fully and left in. I would be very happy if someone could run through those parts and see if any of it can be taken out.
Regarding performance, I've tried to add approx 20 shapes to a scene and then letting all collide with each other (its in one of the movies actually). I noticed no performance degradation at all with those simple shapes (they had a 6 sided box as collision mesh.
The boulders in the last movie have an approx 25 faced hedra inside it as a collision mesh. I think I had 15 of those in an scene without performance degradation.
These shapes do have 1 problem though, and that is the collision detection that sometimes fails - exactly as vehicles. If they gain too much speed they will dip into the terrain or go through it. I think a lot of people are looking into that problem at the moment here www.garagegames.com/mg/forums/result.thread.php?qt=17384
Enjoy ;-)
History
2005-09-08 Updated with performance fix from XoCluTch
What is this?
For my game I needed a boulder that rolls down a hill, and that one needs to evade. Initial attempts to use the existing classes (items, shapes and especially projectiles) fail because of too simple physics and/or lack of collision box support. I was faced with either implementing collision boxes in the projectile class, look into ODE or try to code my own rigid body class.
Thanks to Ben Garney I didnt have to do any of these (thanks ;-) ), as there already exists rigid physics in the engine. The rigid.cc/h files have everything needed, but they are only available as con/net objects using the vehicle classes.
So I simply took the base vehicle class and the hover vehicle class, merged them together and removed most of the unneeded code. The result is actually fantastic, and I cant believe this isnt standard part of Torque.
As the code basically is a hover vehicle there might be parts of the code that should be removed further. If you spot any of those, then post here and I'll update the codebase.
What does it look like?
No resource without a movie :-)
Here is the final result from a tech demo level in my upcomming action adventure game.
www.codejar.com/rigidshape4.wmv
I also did a few early tests and I've included the movies here. The lack of realism is totally due to way too much impulse applied with a large vertical factor + low mass for the chests.
www.codejar.com/rigidshape.wmv
www.codejar.com/rigidshape2.wmv
www.codejar.com/rigidshape3.wmv
All movies are approx 3 MB
How to add
First thing is to add the 2 attached files in the zip to your engine\game dir and to your project. Then open the shapebase.h and find this
class ShapeBaseConvex : public Convex
{
typedef Convex Parent;
friend class ShapeBase;
friend class Vehicle;and add
friend class RigidShape;
Also in the same file down the bottom find this
#define StaticShape_GenericShadowLevel 2.0f #define StaticShape_NoShadowLevel 2.0f
and add
#define RigidShape_GenericShadowLevel 0.7f #define RigidShape_NoShadowLevel 0.2f
Recompile your engine and thats it.
If you want to do this "for real", then one also needs to define a new objectType. I have reused the ShapeBaseObjectType - change that if you want or go through tons of code and add a RigidShapeObjectType.
How to use
From script you now got access to a RigidShapeData datablock and a RigidShape object type. Your DTS object is required to have a mass node, but nothing else. The code still includes dusttrail and splash emitters from the vehicle code, as well as impact + water sound. This example does not use any of those.
An example datablock for a rigid shape is included below
datablock RigidShapeData( BouncingBoulder )
{
category = "RigidShape";
shapeFile = "~/data/shapes/boulder/boulder.dts";
emap = true;
// Rigid Body
mass = 500;
massCenter = "0 0 0"; // Center of mass for rigid body
massBox = "0 0 0"; // Size of box used for moment of inertia,
// if zero it defaults to object bounding box
drag = 0.2; // Drag coefficient
bodyFriction = 0.2;
bodyRestitution = 0.1;
minImpactSpeed = 5; // Impacts over this invoke the script callback
softImpactSpeed = 5; // Play SoftImpact Sound
hardImpactSpeed = 15; // Play HardImpact Sound
integration = 4; // Physics integration: TickSec/Rate
collisionTol = 0.1; // Collision distance tolerance
contactTol = 0.1; // Contact velocity tolerance
minRollSpeed = 10;
maxDrag = 0.5;
minDrag = 0.01;
triggerDustHeight = 1;
dustHeight = 10;
dragForce = 0.05;
vertFactor = 0.05;
normalForce = 0.05;
restorativeForce = 0.05;
rollForce = 0.05;
pitchForce = 0.05;
};By including the category="" it now shows up in the world editor under the Shapes, and its fully working. Spawn the object on a hilltop and see it roll down :-)
For the mission editor to work you will need to add a create() function that hooks into the mission editor. You can either put this into a rigidShape.cs file (dont forget to load it from game.cs) or put it into any .cs file in the server\script
// Hook into the mission editor.
function RigidShapeData::create(%data)
{
// The mission editor invokes this method when it wants to create
// an object of the given datablock type.
%obj = new RigidShape() {
dataBlock = %data;
};
return %obj;
}If you want to have a little fun pushing things around then add this to your player onCollision:
function Armor::onCollision(%this,%obj,%col)
{
...
if (%col.getDataBlock().getName() $= "BouncingBoulder") {
// Apply an impulse to the object we collided with
%eye = %obj.getEyeVector();
%vec = vectorScale(%eye, 10);
// Add a vertical component to give the item a better arc
%dot = vectorDot("0 0 1",%eye);
if (%dot < 0)
%dot = -%dot;
%vec = vectorAdd(%vec,vectorScale("0 0 2",1 - %dot));
// Set the object's position and initial velocity
%trans = %col.getTransform();
// Heres the position and rotation.
%pos = getWords(%trans, 0, 2);
%col.applyImpulse(%pos,%vec);
}
...
}I've done a few tests with forces, masses and such - and as you saw from my movies with varying results.
The objects are fully network aware, and I bet this code can replace ODE for most purposes if you dont need total realism.
As I wrote earlier, the code can be stripped down further. There are various pieces of the physics that I do not understand fully and left in. I would be very happy if someone could run through those parts and see if any of it can be taken out.
Regarding performance, I've tried to add approx 20 shapes to a scene and then letting all collide with each other (its in one of the movies actually). I noticed no performance degradation at all with those simple shapes (they had a 6 sided box as collision mesh.
The boulders in the last movie have an approx 25 faced hedra inside it as a collision mesh. I think I had 15 of those in an scene without performance degradation.
These shapes do have 1 problem though, and that is the collision detection that sometimes fails - exactly as vehicles. If they gain too much speed they will dip into the terrain or go through it. I think a lot of people are looking into that problem at the moment here www.garagegames.com/mg/forums/result.thread.php?qt=17384
Enjoy ;-)
#242
06/18/2008 (12:34 pm)
Isn't there a special "object type" that rigid shape objects use... and thus can be tested for in the player code in C++?
#243
Within RigidShape::RigidShape() it has mTypeMask |= VehicleObjectType; does that mean all rigid objects use VehicleObjectType even if their not vehicles?
Any Ideas how I can test a collision against an object type. Sorry I am very new to programming with torque.
What I have been trying to do is cast a ray from the player to test for a collision against this objecttype. Is this the right way to approach it?
The reason for doing this is to define a new animation to play when coliding with the object. Is a better method to try to be able to change the animation in the script file? I figured this wasnt the right approach because no other animations were defined in the script.
Any help is greatly appreciated.
06/18/2008 (4:28 pm)
Theres a StaticShapeObjectType so I thought there would be a RigidShapeObjectType but I cant find anything on this in the code. Within RigidShape::RigidShape() it has mTypeMask |= VehicleObjectType; does that mean all rigid objects use VehicleObjectType even if their not vehicles?
Any Ideas how I can test a collision against an object type. Sorry I am very new to programming with torque.
What I have been trying to do is cast a ray from the player to test for a collision against this objecttype. Is this the right way to approach it?
The reason for doing this is to define a new animation to play when coliding with the object. Is a better method to try to be able to change the animation in the script file? I figured this wasnt the right approach because no other animations were defined in the script.
Any help is greatly appreciated.
#244
If you realize that this class was made by one of the users for their own purposes, and GG just dropped it into the standard codebase, what you're not finding will make more sense.
06/18/2008 (6:24 pm)
No, you'll need to either add it as a new objecttype or replace one of the existing ones. I'm not a proper programmer, a friend hacked it in for me. hmmm it looks like I'm not using it in my current codebase. Let me know if you can't get it in there and I'll dig around in my backups.If you realize that this class was made by one of the users for their own purposes, and GG just dropped it into the standard codebase, what you're not finding will make more sense.
#245
06/18/2008 (6:30 pm)
Thanks lee. I thought I had it figured with the VehicleObjectType because when I messed about with it the game started crashing. Ill look into adding it as a new object in the morning its getting late.
#246
into the list in game/objectTypes.h. Then change game/rigidShape.cc to use that instead of "VehicleObjectType" when a RigidShape is created. Then test for this object type in the C++ code in player.cc as needed.
06/19/2008 (7:01 am)
Just add something like:RigidShapeObjectType = BIT(29)
into the list in game/objectTypes.h. Then change game/rigidShape.cc to use that instead of "VehicleObjectType" when a RigidShape is created. Then test for this object type in the C++ code in player.cc as needed.
#247
Point3F pos;
Point3F oldPos;
RayInfo info;
if(mActionAnimation.action == PlayerData::RunForwardAnim)
{
if (getContainer()->castRay( oldPos, pos, sCollisionRigidMask, &info))
{
mActionAnimation.action =PlayerData::JumpAnim ;
}
}
I know I'm probably completely off here, I dont really understand the raycast stuff. the sCollisionRigidMask is defined elsewhere like this
static U32 sCollisionRigidMask = (RigidShapeObjectType);
06/19/2008 (8:50 am)
Thanks for the help I've created the new object type. Surely that meens however that it was using the vehicle object type so it should have still worked if I had been able to detect the collision properly. Can anyone help me with detecting the collision this is what ive been trying so far and I crash when I look at the rigiid shape,Point3F pos;
Point3F oldPos;
RayInfo info;
if(mActionAnimation.action == PlayerData::RunForwardAnim)
{
if (getContainer()->castRay( oldPos, pos, sCollisionRigidMask, &info))
{
mActionAnimation.action =PlayerData::JumpAnim ;
}
}
I know I'm probably completely off here, I dont really understand the raycast stuff. the sCollisionRigidMask is defined elsewhere like this
static U32 sCollisionRigidMask = (RigidShapeObjectType);
#248
I want to throw an object out of the players hand with an impulse attached to it running on a schedule like so.
function throwRock()
{
new RigidShape(rock)
{
dataBlock = blueRock;
position = %initRockPos;
};
rock.applyImpulse(rock.position, %EyeVec);
applyRockSchedule();
}
function applyRockSchedule()
{
rock.applyImpulse(rock.getPosition(), "0 0 10");
$rockSched1 = schedule(300,0, applyLift);
}
function cancelRockSchedule()
{
cancel($rockSched1);
}
I would like to cancel the schedule once the rock hits the ground.
I figured it would be as ease as this.
function blueRock::onCollision()
{
cancelRockSchedule();
error ("collision");
}
Fortunately once I call the throwRock() function, on a mouse click during runtime, the rock is created, is thrown properly, and has a bounce to it as it flies through the air.
Unfortunately, once it hits the ground and loses momentum it continues to bounce in place.
Any suggestions on why the onCollision isn't being called would be greatly appreciated.
I'm not sure if its due to the fact I'm creating the object during runtime, or the fact that RigidShape objects don't use ground collision. Maybe I'm just overlooking something as usual.
08/13/2008 (5:39 am)
I have been messing around with this for a few weeks now but am having problems detecting when the object hits the ground.I want to throw an object out of the players hand with an impulse attached to it running on a schedule like so.
function throwRock()
{
new RigidShape(rock)
{
dataBlock = blueRock;
position = %initRockPos;
};
rock.applyImpulse(rock.position, %EyeVec);
applyRockSchedule();
}
function applyRockSchedule()
{
rock.applyImpulse(rock.getPosition(), "0 0 10");
$rockSched1 = schedule(300,0, applyLift);
}
function cancelRockSchedule()
{
cancel($rockSched1);
}
I would like to cancel the schedule once the rock hits the ground.
I figured it would be as ease as this.
function blueRock::onCollision()
{
cancelRockSchedule();
error ("collision");
}
Fortunately once I call the throwRock() function, on a mouse click during runtime, the rock is created, is thrown properly, and has a bounce to it as it flies through the air.
Unfortunately, once it hits the ground and loses momentum it continues to bounce in place.
Any suggestions on why the onCollision isn't being called would be greatly appreciated.
I'm not sure if its due to the fact I'm creating the object during runtime, or the fact that RigidShape objects don't use ground collision. Maybe I'm just overlooking something as usual.
#249
I am making a simple pinball game to help me learn how to work with torque engine better.
So I made the pinball a RigidShape object, and I have it so when it hits a StaticShape object it applies a force that makes the ball fly off in a different direction.
Unfortunately I get the follow problems.
First: I want to delete the ball when it leaves the screen, but when I call %obj delete() I get a crash. I am away from my dev computer so I can't remember where it died at but I think it was doing some collision checking. Did anyone else have this problem, and or a solution?
Does torque have a safe delete, where it doesn't delete the object until everything thing is done with it, or something like that (I found one for TGB, but no luck in TGE)?
Second: When I apply an impulse the ball moves, but then it get all jittery and sometimes it goes through the board, and or moves with out hitting anything that causes an impulse (such as bumper or flippers). Is this a typical issues with this shape? Does the impulse keep get sent after you call it once?
Here is the collision code
function Pinball::onCollision(%this,%obj,%col, %vec, %speed)
{
//if it is colliding with it's self or the terrain, ignore it
if(%obj == %col || %col.getType() & $terrainObjectType)
{
error("Collision with the ball is itself?? or terrainObject");
return;
}
%oName = %obj.getDataBlock().getName();
%cName = %col.getDataBlock().getName();
if( %cName $= "bumpers" )
{
echo( "Pinball hit with speed: " @ %speed @ " and %vec: " @ %vec );
%vecTest = VectorScale( %obj.getVelocity(), $bumpFact );
%obj.applyImpulse(%obj.getPosition(), %vecTest);
}
}
Looking at RigidShape I am wondering does all the physics ad collision get calculated there?
Basically if I need to write better physics for this would I do it all in the RigidShape object or do I have to connect to other part of the engine.
Thanks.
09/14/2008 (12:03 am)
I was really excited when I saw this resource because I though I wouldn't have to implement a physics engine, but now I am having two problems.I am making a simple pinball game to help me learn how to work with torque engine better.
So I made the pinball a RigidShape object, and I have it so when it hits a StaticShape object it applies a force that makes the ball fly off in a different direction.
Unfortunately I get the follow problems.
First: I want to delete the ball when it leaves the screen, but when I call %obj delete() I get a crash. I am away from my dev computer so I can't remember where it died at but I think it was doing some collision checking. Did anyone else have this problem, and or a solution?
Does torque have a safe delete, where it doesn't delete the object until everything thing is done with it, or something like that (I found one for TGB, but no luck in TGE)?
Second: When I apply an impulse the ball moves, but then it get all jittery and sometimes it goes through the board, and or moves with out hitting anything that causes an impulse (such as bumper or flippers). Is this a typical issues with this shape? Does the impulse keep get sent after you call it once?
Here is the collision code
function Pinball::onCollision(%this,%obj,%col, %vec, %speed)
{
//if it is colliding with it's self or the terrain, ignore it
if(%obj == %col || %col.getType() & $terrainObjectType)
{
error("Collision with the ball is itself?? or terrainObject");
return;
}
%oName = %obj.getDataBlock().getName();
%cName = %col.getDataBlock().getName();
if( %cName $= "bumpers" )
{
echo( "Pinball hit with speed: " @ %speed @ " and %vec: " @ %vec );
%vecTest = VectorScale( %obj.getVelocity(), $bumpFact );
%obj.applyImpulse(%obj.getPosition(), %vecTest);
}
}
Looking at RigidShape I am wondering does all the physics ad collision get calculated there?
Basically if I need to write better physics for this would I do it all in the RigidShape object or do I have to connect to other part of the engine.
Thanks.
#250
The delete crashing issues is because I am calling it in a callback.
I was doing "%obj.delete()" which crashed the system. Now I am calling "%obj.scheduale(0, "delete");" which I am guessing it delete the object after it does all its calculations.
The jitter problem I am guessing is a lag between the client and the server on my computer. The program is only ment to be played on my computer so I changed these
$Pref::Net::LagThreshold = "400";
$pref::Net::PacketRateToClient = "10";
$pref::Net::PacketRateToServer = "32";
$pref::Net::PacketSize = "200";
to these
$Pref::Net::LagThreshold = "1200";
$pref::Net::PacketRateToClient = "40";
$pref::Net::PacketRateToServer = "128";
$pref::Net::PacketSize = "800";
now the ball moves much better and load time is less! :)
Glad I could solve my own problems. :)
09/15/2008 (12:58 pm)
I found solutions to my problems ... at least to the ones I stated in this forum.The delete crashing issues is because I am calling it in a callback.
I was doing "%obj.delete()" which crashed the system. Now I am calling "%obj.scheduale(0, "delete");" which I am guessing it delete the object after it does all its calculations.
The jitter problem I am guessing is a lag between the client and the server on my computer. The program is only ment to be played on my computer so I changed these
$Pref::Net::LagThreshold = "400";
$pref::Net::PacketRateToClient = "10";
$pref::Net::PacketRateToServer = "32";
$pref::Net::PacketSize = "200";
to these
$Pref::Net::LagThreshold = "1200";
$pref::Net::PacketRateToClient = "40";
$pref::Net::PacketRateToServer = "128";
$pref::Net::PacketSize = "800";
now the ball moves much better and load time is less! :)
Glad I could solve my own problems. :)
#251
09/15/2008 (11:23 pm)
Thanks for sharing Nathan!
#252
This doesn't seem to have any affect except that it changes when the "lag icon" is shown on-screen.
The packet rate to client is capped at 32 in NetConnection::checkMaxRate().
The packet rate to server is also capped at 32 in NetConnection::checkMaxRate().
$pref::Net::PacketSize = "800";
The packet size is capped at 450 in NetConnection::checkMaxRate().
So, theoretically, the above changes really only change:
$pref::Net::PacketRateToClient = "10";
$pref::Net::PacketSize = "200";
to
$pref::Net::PacketRateToClient = "32";
$pref::Net::PacketSize = "450";
09/16/2008 (7:03 am)
I wonder why this would have much of an effect given that:Quote:$Pref::Net::LagThreshold = "1200";
This doesn't seem to have any affect except that it changes when the "lag icon" is shown on-screen.
Quote:$pref::Net::PacketRateToClient = "40";
The packet rate to client is capped at 32 in NetConnection::checkMaxRate().
Quote:$pref::Net::PacketRateToServer = "128";
The packet rate to server is also capped at 32 in NetConnection::checkMaxRate().
$pref::Net::PacketSize = "800";
The packet size is capped at 450 in NetConnection::checkMaxRate().
So, theoretically, the above changes really only change:
$pref::Net::PacketRateToClient = "10";
$pref::Net::PacketSize = "200";
to
$pref::Net::PacketRateToClient = "32";
$pref::Net::PacketSize = "450";
#253
12/03/2008 (11:25 am)
Wow!!! Talk about me being late to the Party!! I needed some type of way to "push" objects around inside of my game. The point of the game is to allow you to manipulate your enviorment to solve puzzles. This is perfect!!! I'm late but this resource is really nice
#254
Change this:
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticTSObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
To this:
const U32 sCollisionMoveMask = (AtlasObjectType | TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticTSObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
And now everything should work :-).
01/03/2009 (6:20 am)
There is a bug in TGEA Rigid Shape - if you're using Atlas terrain the rigid stuff falls through it. To prevent this from happening make following change in rigidShape.cpp:Change this:
const U32 sCollisionMoveMask = (TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticTSObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
To this:
const U32 sCollisionMoveMask = (AtlasObjectType | TerrainObjectType | InteriorObjectType |
PlayerObjectType | StaticTSObjectType |
StaticShapeObjectType | VehicleObjectType |
VehicleBlockerObjectType);
And now everything should work :-).
#255
05/18/2013 (10:05 pm)
I can't figure out how to figure out for the player to push an object like a ball
#256
There aren't currently any rigidshape objects in my game, but the code is still there and you could add them and experiment in the mission editor in it (and examine the script code).
I ended up removing them because the physics wasn't very realistic, and it was a cpu hog--but it's still very cool and may work fine for what you want to do.
05/19/2013 (12:41 pm)
You need to do stuff in the onCollision methods in script for the player and/or the rigidshape. Check my profile for my game--the scripts are included with it and you can download and see.There aren't currently any rigidshape objects in my game, but the code is still there and you could add them and experiment in the mission editor in it (and examine the script code).
I ended up removing them because the physics wasn't very realistic, and it was a cpu hog--but it's still very cool and may work fine for what you want to do.

Torque Owner Luke Smith