Play simulates rigidbodies on the physics engine Rapier 2D (#146): they fall, slide, bounce, tip over and come to rest. What has no rigidbody behaves exactly as it did before the engine — see Without a rigidbody below.
The rigidbody
A rigidbody is an asset placed as a child of the object it moves, like a collider. Right-click an object in Scene objects → Add rigidbody… and pick Create new rigidbody or one the project has already (searchable, the same as for colliders, #222); an object takes one at most, and a collider, a behavior, a tilemap or another rigidbody takes none. It is drawn as a green ring with an arrow in edit mode and not at all in the game. Its rows:
| Row | Default | What it does |
|---|---|---|
| Body type | Dynamic | Dynamic falls and is pushed. Static never moves on its own. Kinematic goes wherever the object is put (a graph, an animation) and pushes dynamic bodies out of its way. |
| Mass (0 = auto) | 0 | 0 lets the colliders' density and size decide; anything else is the mass itself, in kg. |
| Gravity scale | 1 | How strongly the scene's gravity pulls; 0 floats, -1 falls upwards. |
| Linear damping | 0 | Slows the movement down by itself, like air. |
| Angular damping | 0 | The same for turning. |
| Fixed rotation | off | On: the body never turns (a player). Off: a box that lands on an edge tips over. |
| Continuous (CCD) | off | For small, fast bodies that would otherwise pass through thin walls between two steps. |
The body carries every collider below its object — the object's own collider children and those of objects parented further down, unless one of those has a rigidbody of its own. A rigidbody that is switched off is as if it were not there. A body without any solid collider still falls, with its mass or 1 kg.
A dynamic body is simulated in world units, also below a turned or scaled parent; what the engine works out is handed back as the object's position and rotation, relative to its parent. An object without rotation rows (a camera) never turns. Scaling an object while playing builds its shapes again. Putting a dynamic object somewhere else from a graph moves the body there and keeps its speed.
The material
Every collider has three more rows, read wherever a rigidbody takes part:
| Row | Default | |
|---|---|---|
| Friction | 0.5 | How much it grips. Two colliders meeting use the average of both. |
| Bounciness | 0 | 0 stays down, 1 bounces back as high as it fell. Two colliders meeting use the larger of both, so a ball bounces on plain ground. |
| Density | 1 | Mass per area, in kg per square metre. |
A trigger (isTrigger) weighs nothing and never pushes; it only reports.
A solid tile has Friction and Bounciness too (#193), with the same defaults and the same
mixing, shown in the inspector once Solid is on. It has no Density: a map never moves, so what its
cells would weigh counts for nothing. Tiles of different surfaces never merge into one rectangle,
so an ice patch in a stone floor is its own shape, and Move slides along each cell by the tile it
belongs to (see Tilemaps). The scene view still outlines the floor as one.
Shapes in the engine
A capsule collider is the engine's capsule; a polygon, and a Frame collision collider, is one convex polygon per piece it is cut into (see Colliders), all on the same body, so a concave shape rests and rolls as the shape it is — a crate dropped into a U lands on its inner floor, not on the lid across the notch. A rigidbody's fixed Mass is shared out among the pieces by area, and density weighs each by its own area.
A body that lands fast sinks in a little before the engine pushes it back out: measured 0.9 units for a capsule landing at about 6 units a frame, 0.02 twenty frames later.
Gravity and units
The scene has Gravity X and Gravity Y, default (0, 980). Everything is in world units (pixels); the engine works in metres and 100 units are one metre, so 980 is the Earth's pull. It is read every frame, so an animation over the scene can change it while playing.
The engine steps at a fixed 60 steps per second, whatever the frames take; a frame that took longer catches up with at most 8 steps and forgets the rest, so a hitch does not make the game run fast for a while after. What the game view shows of a dynamic body lies between the last two steps, so it moves evenly on any display — which also means it is drawn up to one step (1/60 s) behind the engine.
On fixed update (see Behaviors) runs exactly as often as the engine steps. It does
not run in between the steps, though: the engine takes all of a frame's steps first, the behaviors
come after. A force set in On fixed update therefore acts from the next frame's steps on.
Collision events
On collision enter/stay/exit and Is touching come from the engine's contact pairs.
On collision enter and On collision stay have five more outputs: normal x and normal y,
a unit vector pointing from the other collider towards the own one — (0, -1) for something landing
on the ground — impulse, how hard they meet (kg · units per second), and point x/y, the middle
of the contact points in the world. Enter tells how the pair met, stay how it touches at the moment
it fires (#149) — which, with its Interval (s), need not be every frame. The impulse is the
engine's own number: it grows with the weight, but a crate at rest reports about 1.25 times
mass · gravity · 1/60, not exactly that (measured). A trigger reports all of them as 0, and so does
the editor run, which simulates nothing. Is touching answers for the last step, not for a move
made in the same frame.
Without a rigidbody
An object with colliders but no rigidbody is what every project was before: its colliders go
wherever the object is put, nothing pulls on them, and dynamic bodies bounce off them as off a wall.
Whether two of them touch is decided by the same overlap test as before — touching edges do not
count, only overlapping does — the engine only proposes which pairs to test. A placed tilemap is
static ground made of its merged solid cells (see Tilemaps). Move with
Collide with solids works as described in Colliders: the object stops flush at what
is in its way and goes on along its surface, less what friction takes — the same friction a
dynamic body feels, combined the same way (the average), and the same in Play and the editor run.
A dynamic body that stops such a move gets pushed into the contact — along its normal, so a crate hit at its corner is shoved away from the corner, not along the move — as one body meeting another without bounce: the speed it is pushed with is the move spread over the frame, and how much of it the body takes depends on the two masses — a mover as heavy as a crate shoves it along, a crate forty times heavier hardly shifts (measured: 133 of 161 units in a second, and 0.2). The mover weighs what its rigidbody's Mass says, or else what its colliders weigh by their density; a dynamic mover what the engine says. The mover stays flush in front of the crate and never gets into it.
One-way colliders in the engine
A dynamic body lands on a one-way collider or tile (see Colliders) and passes
it from below and from the side, like Move does. The engine is told pair by pair whether to push
the two apart (Rapier's filterContactPair hook). Its JavaScript version cannot touch the engine
from inside the hook — even reading a body's position there throws, the throw is swallowed and the
pair collides with nothing (found in the spike for #155) — so the answer for each dynamic body near a
one-way collider is worked out before every step:
- It lands when it is on the blocking side or sunk in no deeper than 2 units (a landing at 60 steps per second sinks in 1.9 before the engine pushes it out), the contact faces that side within the collider's or tile's one-way angle (45 degrees by default, #159), and it is not moving away from it.
- Once landed it is held as long as the two overlap: a body falling 2000 units per second is 13 units into an 8 units thick platform one step later, and is pushed back up instead of passing.
- Otherwise it passes, and so does a body told to by
Ignore one-way. A resting body is woken for that — a sleeping one would not fall by itself.
Measured in the spike at 60 steps per second: a landing sinks in 1.9 units and rests 0.009 deep, a body shot up from below comes out on top and lands, one sliding sideways goes through, and one falling at 2000 units per second lands with and without CCD. Collision events come on passing through as well: overlapping is colliding.
Collision layers in the engine
Rapier has the rule built in: every collider gets an interaction group, its layer in the high
16 bits and its Collides with mask in the low ones, set as both the collision group (what is
detected) and the solver group (what is pushed apart). The engine meets a pair when each side's
membership passes the other's filter, which is exactly what
layersMeet says — so a pair that the layers keep apart is not
reported either, and nothing extra has to be filtered afterwards. Changing a layer rebuilds the
body's colliders, since the group sits on the collider itself.
Moving bodies from a graph
| Node | What it does |
|---|---|
| Apply force | Pushes with a force (units · kg per second²) for the length of the frame, so from On update it pushes steadily at any frame rate. A heavier body speeds up less. |
| Apply impulse | A kick at once (units · kg per second): the velocity changes by impulse ÷ mass. A jump, a hit, an explosion. |
| Set velocity | Sets the speed in units per second, whatever the body weighs. For one direction only, feed the other from Get velocity. |
| Set angular velocity | Sets the turning speed in degrees per second, counted like the rotation. A body with Fixed rotation does not turn, and does not start to later either. |
| Get velocity | Speed (x, y) and turning speed (degrees/s); 0 for an object without a dynamic body. |
| Joint position | How far a hinge has turned or a slider has glided from how it was placed, and how fast; see Joints. |
| Set gravity | The scene's gravity for the rest of the run; the next scene starts with its own, and the project keeps its value. |
The object is the one the rigidbody sits on (the rigidbody itself works too). They act on a
dynamic body only; on anything else they do nothing, and the console says so once per object:
Physics: "Player" has no dynamic rigidbody, so Apply force, Apply impulse and Set velocity do nothing on it. They work from On start on.
Move and Set position on a dynamic body put it somewhere else and it keeps its velocity; the
first time the console points to the nodes above, which move it with the physics.
Dragging a dynamic body in the scene view while the game plays (the object, its rigidbody, or an object above it) takes it out of the simulation for as long as the mouse holds it: it follows the pointer as if it had no rigidbody, and gravity does not pull it. Let go, it starts again at rest, with no velocity.
Joints
A joint ties the object it sits on to another one (#154). It is an asset placed as a child of the object it holds, like a collider or a rigidbody: right-click the object in Scene objects → Add joint… and pick Create new joint or one the project has already. An object takes as many as it needs; a collider, a behavior, a rigidbody, a tilemap or another joint takes none. In the scene view it is the icon of two ends on a bar, and it is not drawn in the game.
Where the joint sits is the point it holds its object at — move the joint and that point moves. Its rows:
| Row | Default | What it does |
|---|---|---|
| Type | Hinge | Hinge: the object turns round the point where the joint sits (a door, a pendulum, a wheel). Spring: pulled towards a length, swinging about it. Rope: free up to a length, held beyond it. Fixed: kept exactly as the two were placed, moving as one. Slider: the object glides along one line and does not turn against the other end (a lift, a piston, a drawer). |
| Connected object | None | The other end, picked from the objects of the scene or with the eyedropper. None is a point of the scene that never moves. |
| Connected anchor X / Y | 0, 0 | Spring and rope only: where the other end is, in the connected object's own units (0, 0 is its origin, and it turns and scales with it) — with no connected object, in the scene's. A hinge and a fixed joint have one point only, the one the joint sits on. |
| Length (0 = as placed) | 0 | Spring and rope only: the length the spring rests at or the rope allows, in world units. 0 takes the distance between the two ends as they were placed. |
| Stiffness | 50 | Spring only: the force per 100 units of stretch (N/m). A body of 1 kg on 40 swings once in 0.99 s. |
| Damping | 1 | Spring only: how fast the swinging dies down; 0 swings on. |
| Limit angle | off | Hinge only. On: Min angle and Max angle say how far the object turns either way, in degrees, counted from how it was placed. |
| Limit distance | off | Slider only. On: Min distance (default -100) and Max distance (100) say how far the object glides either way, in world units, counted from where it was placed. |
| Motor | Off | Hinge and slider only. Speed: turns or glides on at Motor speed. Target: goes to Motor target at no more than Motor speed, slows down for the last stretch and holds there. |
| Motor speed | 90 | Degrees a second for a hinge, world units a second for a slider. Positive turns the way a positive rotation does (clockwise on screen), or glides along the rail's direction. |
| Motor target | 0 | Target only: where to go, in degrees or world units counted from how the joint was placed, like the limits. |
| Max force (0 = no limit) | 0 | Speed and Target: the most the motor pushes with, in units · kg per second² as Apply force counts; for a hinge, pushing 100 units from its pin. Something heavier or in the way stops it. 0 is as strong as it takes. |
| Collide with connected | off | Off: the two objects of the joint pass through each other. On: they collide like any two. |
A joint has Scale, Rotation and Mirror X/Y like a sprite, and the knob of the scene view turns it. Only a slider uses them: its rail is the joint's own x axis, so rotation 0 is a level rail and 90 an upright one whose positive direction points down. The joint turns with the object it sits on, as every child does. A slider held to the scene, or to an object without a rigidbody, keeps its object turned as it was placed. Between two rigidbodies the engine keeps the two at one angle, so it turns the held object to match the other once, and the console says so.
The object needs a rigidbody, its own or one of an object above it. Without one the joint holds
nothing and the console says so once: Physics: "Lamp joint" sits on an object without a rigidbody, so it holds nothing.
The connected object need not have one. With a rigidbody the two pull on each other. Without
one it is a moving anchor: nothing pulls it, but the joint follows it wherever a behavior or an
animation puts it — a lamp on a platform that drives along. A connected object that is destroyed
while the game runs makes the joint let go (… lost its connected object, so it holds nothing.);
removed in the editor, the row goes back to None like any reference to it (#269), so the joint then
holds on to the scene. A joint connected to the object it sits on holds nothing either.
A reference follows its object as every object's place does (see Behaviors): pasted together, the copy of the joint names the copy of the other object, and inside a container every placement holds on to its own copy.
In the scene view a line leads from the joint to what it holds on to: to the connected anchor of a spring or a rope, to the connected object of a hinge or a fixed joint. The held point is ringed, since the icon stands aside when it shares the spot with a collider's. A selected spring or rope has a round handle on its far end: drag it to move the connected anchor (one undo step). A slider also gets its rail, dashed through where the joint sits: between its limits, with a tick at each, or 60 units either way without any. While the game is played the rail is drawn where the joint is, so it travels along with the object.
A joint that is switched off lets go, and holds again when it is switched back on. Destroy on a
joint lets go for good. Add joint ties two objects while the game runs: it places the picked
Joint asset on object at (x, y) of that object, connects it to connected (nothing there: the
scene) and outputs the new joint. The asset is the template for the type and every value;
Properties with Type Joint changes them on a placed joint. Setting Motor speed, Motor
target or Max force that way changes the running motor, so a door opens by writing 90 into its
target. Joint position reads a hinge or a slider back: value is how far it has turned
(degrees, counting on past a full round) or glided (world units) from how it was placed, and
speed how fast that changes. It is 0 for the other types, for a joint that holds nothing, and in
the editor run.
A motor pushes on the turn only, so a hinge drives a door well but is weak on a small object at the end of a long arm. Measured: a door of 100 x 20 hinged at its end reaches -90 degrees and holds it against gravity. A box of 20 on an arm of 100 at the same 180 degrees a second swings past a target of 90 to 105 without gravity, and with gravity it does not lift itself. The engine works the turn out over too few rounds for that. A wheel turning round its own middle has no such trouble.
Joints hold while the game is played. The editor run simulates nothing (#148), so there they do nothing, and the inspector of a placed joint says so.
Measured in the unit tests: a pendulum of 100 units crosses the middle after 0.50 s (2.007 s the whole period), a spring of 40 N/m on 1 kg turns round after 0.50 s, a rope of 150 lets a body fall to 150 and no further, and a hinge limited to 30 degrees stops between 27 and 33. A wheel with a motor of 360 degrees a second has turned 880 to 905 degrees after 2.5 s, a lift driven to -200 holds there, and a slider limited to 50 stops between 48 and 52.
Play and the editor run
The editor loads the engine right after opening the project; Play waits for it if it is not there yet (Loading the physics engine…), and does not start if it could not be loaded — the notice and the console say why. There is no falling back to the old detection: a game would collide differently.
A behavior with Run in editor sees collisions but no simulation: dynamic bodies stay where they are placed, because what the editor run moves is saved. The nodes above do nothing there.
What is not there yet
Movestepping up onto a ledge, or a limit on how steep a slope it walks up — that is for the graph, withhitandnormal(#150).Movedoes not use Rapier's character controller: in #147 it caught on the seams between boxes lying side by side (10 of 100 steps along a floor of 12 crates), kept a gap of up to 1.7 units and knows no friction;Moveworks out its contacts itself, in double precision, and slides over the same seams without catching (#150).- The simulation in the editor run (#148).
- A force that breaks a joint. Raycasts (#153) with their layer filter (#158),
Raycast allwith every hit on the line (#157), one-way platforms (#155) and the collision layers themselves (#152) are there, see Colliders.
Using the editor
- Concepts
- Accounts
- Agents (MCP)
- Scenes
- Scene editing
- Behaviors
- Structs
- Colliders
- Physics
- Textures
- Vector art
- Pixel art
- Fonts
- Videos
- Sounds
- Instruments
- Patterns
- Songs
- Animations
- Curves
- Tiles
- Tilemaps
- State machines
- Shaders
- Particles
- Containers
- Compositions
- Keyboard
Working on the code