Click or drag to resize
DigitalRuneThe Simulation
The Simulation class

The class Simulation is the core of the physics library. The simulation manages collections of

  • RigidBodies, which represent static or movable solid objects,
  • ForceEffects, which are effects that apply forces on rigid bodies and create motion (e.g. Gravity), and
  • Constraints, which restrict the motion of rigid bodies (e.g. contact constraints stop objects from moving through other solid objects, joints connect bodies, motors create motions, etc.).

Objects in these collections take part in the simulation. All object that should be simulated need to be added to these collections. Objects that are not added to these collections are ignored by the simulation.

Simulation settings

The simulation has several configurable simulation parameters. These can be changed using the property Settings of the simulation. See also DigitalRune.Physics.Settings and Class Diagram of Namespace DigitalRune.Physics.Settings.

Advancing the simulation

To advance the simulation the method Update must be called with the time span by which the simulation time should advance. In Update the simulation computes forces and moves the rigid bodies to new positions. One step of the simulation is called a "time step".

The "World" rigid body

The simulation owns a special rigid body: SimulationWorld. This rigid body represents the "world" of the simulation. This rigid body is not contained in the SimulationRigidBodies collection and other bodies do not collide with this body. This body is used to define the space in which the simulation takes place. Rigid bodies that leave the space of this rigid body are automatically removed from the simulation. Per default the shape of the World body is a box that is 20,000 units long and centered at the world space origin. - If objects leave this area, they will be removed. A typical scenario is that an explosion or simulation errors shoot objects into nirvana. When they leave the 20,000 units area, they are removed to safe simulation time. You can adjust the shape of the world body to the size of the level or the "area of interest".

The second function of the World body is to act as an anchor for constraints. All constraints are two-body constraints and, for example, if you want to fix a rigid body at a certain position in world space you create a constraint between the rigid body and the world body. See Constraints, Contacts and Joints for more information about constraints.

Collision detection

The Simulation owns a CollisionDomain. Each RigidBody has a CollisionObject that represents the collision information of the body and is automatically put into the collision domain of the simulation that contains the rigid body. (For these collision objects the property CollisionObjectGeometricObject references the RigidBody.)

You are free to use the collision domain to perform collision queries. You can also add custom collision objects into the collision domain - even objects that aren't rigid bodies. For example, you can add a collision object to check if rigid bodies or other collision objects enter a certain area. Or you can perform ray-casts against collision objects.

The collision domain is automatically updated at the begin of a simulation time step. If SimulationSettingsSynchronizeCollisionDomain is set, the collision domain is also updated at the end of a simulation step. This is useful if the game logic makes collision queries and requires up-to-date collision info.

The property ContactUserData is used by the simulation to store references to ContactConstraint instances. Therefore, the ContactUserData property of contacts between rigid bodies must not be changed. In other words, the relationship between Contacts and ContactConstraints is

C#
myContactConstraint.Contact == myContact
myContact.UserData == myContactConstraint

Collision filtering

By default, the narrow phase filter of the collision detection (CollisionDetectionCollisionFilter, see also Collision Filtering) is set to an instance of type CollisionFilter. The filter rules in the CollisionFilter can freely be changed as required by the application. The whole filter can be replaced too, but the new filter should implement the interface ICollisionFilter. If the new collision filter does not implement ICollisionFilter, then automatic collision filtering for constraints does not work (see Constraints, Contacts and Joints and ConstraintCollisionEnabled). Advanced physics modules like ragdoll physics and vehicle physics might also need a collision filter that implements ICollisionFilter.

By default, no broad phase filter is set. (See property Filter of CollisionDomainBroadPhase.)

To improve the performance of the simulation it is recommended to use the collision filters to disable collisions between bodies when the collision information is not required. The simulation does not need collision information between two bodies if both bodies are kinematic or static. The simulation only uses collision information involving dynamic bodies to create contact constraints (see Constraints, Contacts and Joints). Therefore, it can be beneficial to set a collision filter that disables collisions between non-dynamic objects.

Parallel simulations

A game that uses game physics usually uses one instance of Simulation. But it is allowed to use several parallel simulation instances. Parallel simulations can share shape, mass frame or material instances. Rigid bodies, force effects and constraints cannot be shared between simulations; they belong to exactly 0 or 1 simulation.

A basic example

Here is a simple example that shows how to setup the simulation and how to add rigid bodies. The simulation is configured with two force effects: gravity and damping. These force effects are necessary for most scenarios and they should always be added - unless you know what you are doing ;-).

The basic setup:

C#
using DigitalRune.Geometry;
using DigitalRune.Geometry.Shapes;
using DigitalRune.Mathematics.Algebra;
using DigitalRune.Physics;
using DigitalRune.Physics.ForceEffects;

...

Simulation mySimulation = new Simulation();

// Add a gravity force that pulls objects to the ground.
mySimulation.ForceEffects.Add(new Gravity());

// Add a damping effect that models air resistance and slows objects.
mySimulation.ForceEffects.Add(new Damping());

// Add a ground plane.
RigidBody ground = new RigidBody(new PlaneShape(Vector3F.UnitY, 0))
{
  Name = "GroundPlane",
  Pose = Pose.Identity,
  MotionType = MotionType.Static,  // Ground plane should not move.
};
mySimulation.RigidBodies.Add(ground);

// Add a box above the ground with a random orientation.
RigidBody cube = new RigidBody(new BoxShape(1, 1, 1))
{
  Name = "Cube",
  Pose = new Pose(new Vector3F(0, 2, 0), RandomHelper.Random.NextQuaternionF()),
};
mySimulation.RigidBodies.Add(cube);

In each frame of the game, the simulation must be updated by calling following method (usually with 60 fps):

C#
// Advance the simulation.
// deltaTime is the elapsed time since the last simulation update.
mySimulation.Update(deltaTime);