TorqueGameEngine/RigidShape

From TDN

This is an incomplete work in progress.


Contents

Overview

Many people new to TGE are surprised to learn that it includes a physics system.

The purpose of this article is to show how to create and use a RigidShape object in TGE. The RigidShape class implements rigid-body physics for DTS objects in the world. "Rigid body physics" refers to a system whereby objects are assumed to have a finite size, equally distributed masses, and where deformations of the objects themselves are not accounted for.

Here is a list of the fields used in a RigidShapeData DataBlock.

What does that mean?

It would probably work well for billiards balls, but not so great for superballs. In TGE, the RigidShape class is the base class for all vehicles. In versions of TGE prior to 1.4.2, the RigidShape class was not exposed to scripting, unless you exposed it yourself in code (as described in this resource [1]). The RidigShape class does not implement joints, ragdolls, springs, or chains.

Other Physics Systems

Rigid-body physics might be sufficient for your needs; if not, some members of the community have integrated other physics systems into TGE. ODE is a popular open-source library used by a number of games. Newton is another free library that has been discussed in the GarageGames forums. PhysiX is a commercial library that can be used for free under certain conditions.

ODE Newton PhysiX

Note

This article is based entirely on information in Thomas Lund's resource. The RigidShape class was exposed to script in TGE 1.5, but its use was left undocumented, aside from that resource. If you know that resource already, there's nothing new here for you. I'm just cleaning it up for newbies like myself.

Using RigidShape in TGE 1.5

Here's some simple steps to get you started using RigidShape objects in TGE.

Step one: create a RigidShape datablock. In /tutorial.base/server/ create a new file called "boulder.cs":

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;
};


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;
}


function RigidShapeData::onCollision(%data, %obj, %col, %vec, %speed)
{
   //if it is colliding with it's self or the terrain, ignore it
   if(%obj == %col || %col.getType() & $terrainObjectType)
      return;

   error("RigidShapeData::onCollision %col:" SPC %col.getDataBlock().getName());
   error("RigidShapeData::onCollision %obj:" SPC %obj.getDataBlock().getName());

   %normal = vectorDot(%speed, vectorNormalize(%speed));
   if(%normal > 58)
      %scale = %normal / 2;

   %objMass = %obj.getDataBlock().mass;
   %colVel = vectorLen(%col.getVelocity());

   //add some random boost to the Z
   %objVec = getWord(%vec, 0) SPC getWord(%vec, 1) SPC mFloor(getRandom(2, 5));

   %objImpulse = %objMass * ((%speed / 100) + (%colVel / 15));

   //the case is, we don't want to apply an impulse greater then X times the objects mass, so
   //clamp it down, otherwise it might visit the moon
   %objImpulse = %objImpulse / 8 > %objMass ? %objMass * 8 : %objImpulse;

   error("objImpulse:" SPC %objImpulse);

   %obj.applyImpulse(%obj.getWorldBoxCenter(), VectorScale(%objVec, %objImpulse));
}

This creates a datablock based on the RigidShapeData class. In the datablock you set the physical properties used to calculate the forces applied to the object, like the object's mass, center of mass, friction, etc. You also define a DTS shape to be used by the object; here I'm using Thomas Lund's boulder shape. It also implements a function "::create" which is called by the Mission Editor when one of these objects is created. And importantly, it implements "::onCollision" to handle collisions between the itself and other objects. (In Thomas Lund's resource, collisions are handled in the player's ::onArmor method, which meant that objects could collide with the player, but not with other objects. i.e. the player could run into a stack of crates and knock them down; but an AI player couldn't. I've changed this around so that objects themselves handle their collisions, so a wider variety of things in the world can interact.)

Step two: add the following line after line 24 of /tutorial.base/server/game.cs so that the new file is executed:

   exec("./boulder.cs");

It should be in the "onServerCreated()" function.

Step three: download Thomas Lund's boulder and place the DTS shape and texture files into /tutorial.base/data/shapes/boulder/. (You can use a different path, but if so you'll need to adjust the shapeFile property in boulder.cs.)

Clear your DSOs and run TGE. Click "World Editor" to start the F World mission.

= Adding a boulder to the mission

Move the camera to the player (control-c). Hit F11 (control-F11 for Mac users) to turn on the mission editor. Turn on the "World Editor Creator" tool. In the list at the bottom right, you will see a tree list. Expand the items in the tree until you reach the "boulder" item:

+Static Shapes
 +tutorial.base
  +data
   +shapes
    +boulder
     -boulder

Click on the final "boulder" item and a boulder will be instantiated into the world.

Grab its z-axis gizmo handle place it on the ground.

Hit F11 again and control-c so that you're controlling the player. Run into the boulder.