Skip to main content

Rigid Bodies

A rigid body is an entity that takes part in the physics simulation. It needs two components: a rigidbody component, which decides how the physics engine treats the entity, and a collision component, which gives it a shape. A rigidbody component without a collision component has nothing to collide with and does nothing. Shapes are covered on the Collision Shapes page; this page is about the body itself.

Body Types

The type of a rigid body decides who moves it:

  • Static - Never moves. Use it for the ground, walls and anything else that is part of the environment. Static bodies are cheap, and the engine assumes they stay put.
  • Dynamic - Fully simulated. It falls under gravity, responds to collisions, forces and impulses, and the physics engine owns its position and rotation.
  • Kinematic - Moved by you, through the entity's transform. It pushes dynamic bodies out of its way but is not affected by them or by gravity. Use it for moving platforms, doors driven by animation and anything else that follows a script rather than the laws of physics.

Here is a one meter dynamic box that will fall onto whatever is below it:

const box = new pc.Entity('box');
box.addComponent('render', { type: 'box' });
box.addComponent('collision', { type: 'box' });
box.addComponent('rigidbody', { type: pc.BODYTYPE_DYNAMIC, mass: 2 });
box.setPosition(0, 5, 0);
app.root.addChild(box);
Falling Shapes

Mass and Materials

Four properties describe how heavy a body is and how its surface behaves in a contact:

PropertyDescription
MassThe mass of a dynamic body in kilograms. Heavier bodies need more force to accelerate and push lighter ones aside. Defaults to 1 and is ignored by static and kinematic bodies
FrictionHow strongly the surface resists sliding, from 0 to 1. Defaults to 0.5
Rolling FrictionResistance to rolling, which stops spheres and cylinders from rolling forever. Defaults to 0
RestitutionBounciness, from 0 to 1. Defaults to 0. The values of the two bodies in a contact are multiplied together, so a ball with a restitution of 1 does not bounce on a floor with a restitution of 0
entity.rigidbody.mass = 5;
entity.rigidbody.friction = 0.8;
entity.rigidbody.rollingFriction = 0.1;
entity.rigidbody.restitution = 0.6;

Damping and Factors

Two pairs of properties shape how a dynamic body moves once it is in motion:

  • Linear Damping and Angular Damping are the proportion of velocity a body loses each second, from 0 to 1, like air resistance. They default to 0.
  • Linear Factor and Angular Factor scale movement and rotation per world axis. A factor of 0 locks that axis. Setting the angular factor to 0, 0, 0 keeps a character upright; a linear factor of 1, 1, 0 with an angular factor of 0, 0, 1 confines a body to the XY plane for a 2D game. They default to 1, 1, 1.
// Slow the body down over time, like air resistance
entity.rigidbody.linearDamping = 0.2;
entity.rigidbody.angularDamping = 0.2;

// Keep a character upright: no rotation about any axis
entity.rigidbody.angularFactor = new pc.Vec3(0, 0, 0);

// Confine a body to the XY plane of a 2D game
entity.rigidbody.linearFactor = new pc.Vec3(1, 1, 0);

Sleeping

A dynamic body that comes to rest is put to sleep by the physics engine, which stops simulating it until something disturbs it. Applying a force, impulse or torque, assigning a velocity and teleporting all wake a body automatically, as does being hit by another body. You can also wake one yourself:

if (!entity.rigidbody.isActive()) {
entity.rigidbody.activate();
}

Moving and Teleporting

The physics engine owns the position and rotation of a dynamic body, so anything you set on its entity's transform is overwritten on the next step. To move a dynamic body, apply forces or velocities, or call teleport on the rigidbody component when it has to jump somewhere, for example when respawning. Teleporting does not clear the body's velocity, so reset that first if the body should arrive at rest:

// Move to a position, keeping the current rotation
entity.rigidbody.teleport(0, 10, 0);

// Move and rotate, with the rotation given as Euler angles in degrees
entity.rigidbody.teleport(new pc.Vec3(0, 10, 0), new pc.Vec3(0, 90, 0));

// Respawn at rest: clear the old motion, then move and rotate with a quaternion
entity.rigidbody.linearVelocity = pc.Vec3.ZERO;
entity.rigidbody.angularVelocity = pc.Vec3.ZERO;
entity.rigidbody.teleport(spawn.getPosition(), spawn.getRotation());

Kinematic bodies work the other way round. You move the entity with setPosition, setRotation, lookAt and the rest of the transform API, and the body follows on the next step, carrying any dynamic bodies that rest on it:

// A platform that slides back and forth along the X axis
platform.setPosition(Math.sin(time) * 2, 0.5, 0);

Vector properties such as linearVelocity and angularFactor return read-only snapshots. Assign a new vector rather than editing the returned one.

These calls are the same wherever you build. In React, reach the entity with the useParent hook from a component placed inside the <Entity>; in Web Components, through the entity property of the <pc-entity> element. Moving Bodies shows where per-frame code runs on each surface.

Collision Groups and Masks

Every body belongs to a collision group and carries a mask of the groups it collides with. Two bodies interact only when each one's group is in the other's mask. The engine assigns both when the body type is set: dynamic bodies collide with everything, while static and kinematic bodies never collide with each other. You can narrow this from code to stop, for example, projectiles hitting one another:

// Put the body in a user group and stop it colliding with other members of that group.
// Set these after the type, because changing the type resets them.
entity.rigidbody.group = pc.BODYGROUP_USER_1;
entity.rigidbody.mask = pc.BODYMASK_ALL ^ pc.BODYGROUP_USER_1;

Eight user groups, pc.BODYGROUP_USER_1 to pc.BODYGROUP_USER_8, are free for your own use. The same groups and masks filter ray casts.

See Also