Bodies
A Body has a position, an orientation, a velocity and a
mass. It has no shape of its own: collision geometry is
attached to it, and the mass comes from what you attach.
Body types
| Type | Moved by | Mass | Pushed by others | Typical use |
|---|---|---|---|---|
Static |
nothing | infinite | no | Level geometry, terrain |
Kinematic |
you | infinite | no | Platforms, lifts, characters |
Dynamic |
the solver | from its shapes | yes | Anything that falls over |
Static bodies are effectively free, so use them for everything that does not move; they do not collide with each other at all. A kinematic body pushes dynamic bodies out of the way without being pushed back.
Body ground = world.CreateStaticBody(new Vector3(0.0f, -0.5f, 0.0f));
Body crate = world.CreateDynamicBody(new Vector3(0.0f, 5.0f, 0.0f));
Body lift = world.CreateKinematicBody(shaftBase);
For anything the three convenience methods do not cover, build a
BodyDefinition and pass it to CreateBody:
Body projectile = world.CreateBody(BodyDefinition.Dynamic(muzzle) with
{
LinearVelocity = aim * 80.0f,
IsBullet = true,
GravityScale = 0.5f,
Name = "shell",
});
Create bodies where they belong. Creating at the origin and moving afterwards costs nearly twice as much, and more once shapes are attached.
Moving a dynamic body
Forces and impulses are what the solver expects. A force accumulates over the step; an impulse changes velocity immediately.
crate.ApplyForceToCenter(new Vector3(0.0f, 200.0f, 0.0f)); // thruster
crate.ApplyImpulseToCenter(jump); // kick
crate.ApplyForce(wind, atPoint); // off-centre: also spins it
crate.ApplyTorque(new Vector3(0.0f, 5.0f, 0.0f));
crate.ApplyAngularImpulse(spin);
Each takes a wake argument, defaulting to true. Applying a force to a
sleeping body without waking it does nothing.
Setting LinearVelocity directly works and is sometimes what you want, but it
overrides the solver rather than cooperating with it: a body driven that way
walks through a stack instead of pushing it.
Moving a kinematic body
Drive it with LinearVelocity or MoveTowards, not SetTransform:
lift.LinearVelocity = new Vector3(0.0f, 2.0f, 0.0f);
lift.MoveTowards(nextPosition, nextRotation, FixedStep);
SetTransform is a teleport: it does not sweep, so the body can pass through
geometry, and it is expensive. MoveTowards sets the velocity that arrives at
the target pose after one step, so the body keeps a real velocity and its
contacts push other bodies correctly. That is what makes a platform carry what
stands on it.
Mass
Mass, centre of mass and rotational inertia are computed from the shapes on the body and their density. A body with no shapes has neither mass nor geometry, so attach before you simulate.
Body body = world.CreateDynamicBody(spawn);
body.AddBox(Box.Cube(0.5f), ShapeDefinition.Default with { Density = 500.0f });
float kilograms = body.Mass;
Vector3 centre = body.CenterOfMass; // world space
Vector3 local = body.LocalCenterOfMass; // body space
Attaching or destroying a shape recomputes the mass by default. When several
shapes change at once, suppress it with UpdateBodyMass = false and call
RecomputeMass once at the end.
Sleeping
A body that stops moving falls asleep and stops costing anything until something touches it. This is on by default and is a large win: a settled scene of ten thousand bodies steps in roughly the time an empty one does.
world.AwakeBodyCount // zero means the scene has settled
body.IsAwake = true; // wake it yourself
body.CanSleep = false; // this body is stepped every frame, always
Turn sleeping off only when something depends on a body being stepped every
frame. SleepThreshold on the definition sets the speed below which a body is
considered still.
Sleeping is also the classic way to write a benchmark that measures nothing — see Benchmarks.
Restricting motion
Body character = world.CreateDynamicBody(spawn);
character.MotionLocks = MotionLocks.NoRotation; // stays upright
crate.MotionLocks = new MotionLocks { LinearZ = true, AngularX = true };
MotionLocks removes degrees of freedom without
changing mass, which is how you get a body that slides but never tips.
Body space
Vector3 local = body.ToLocalPoint(worldPoint);
Vector3 world = body.ToWorldPoint(localPoint);
Vector3 direction = body.ToWorldVector(localDirection); // rotation only
Vector3 velocity = body.GetVelocityAt(contactPoint); // includes spin
GetVelocityAt is the one to use for impact sounds and damage: a point on a
spinning body moves even when the body's centre does not.
Enabling, disabling, destroying
body.Disable(); // out of the simulation entirely; costs almost nothing
body.Enable();
body.Destroy(); // gone, and every handle to it is now invalid
Disabling is the cheap way to park something you will need again. Destroying
invalidates every Body and Shape handle referring to it — see
Handle validity.