Making games
Physics
Physics needs two things on an object: a Collider, the shape it collides with, and usually a Rigid Body, which says how it moves.
Rigid bodies
| Body type | What it is | Examples |
|---|---|---|
| Dynamic | Moved by physics: falls, bounces, gets pushed. | Crates, balls, ragdolls, the Skyhawk aircraft |
| Static | Never moves. | Floors, walls, terrain |
| Kinematic | Moved only by scripts, but pushes dynamic bodies out of its way. | Moving platforms, doors, elevators |
An object with a Collider and no Rigid Body is static, so a floor needs nothing but a collider.
A dynamic body’s Mass is in kilograms. Linear damping and Angular damping slow it down over time, like air resistance. Gravity scale multiplies gravity for this body alone (0 floats). Can rotate off keeps it upright, and Can sleep lets a body that has come to rest stop costing anything until something touches it.
Smooth motion
Physics runs at a fixed 60 steps a second, whatever the frame rate, so a frame can fall between two steps or take two at once. A moving body is therefore drawn between its last two physics steps, so it moves as smoothly as the display rather than in physics-sized jumps. This is on for every project and every moving body; Physics interpolation under Project Settings → Display turns it off.
Only what is drawn changes. Scripts, raycasts and collisions always see where a body really is, which can be up to one step (1/60 s) ahead of what is on screen. Moving a body from a script, by setting its position or rotation, is drawn at once rather than blended, and a script that sets only the rotation (a character turning with the mouse) leaves the movement smooth. A camera that follows a body moves smoothly if it is a child of that body; one that copies the body’s position in a script copies the true position, and can look a step out of time with it.
Colliders
| Shape | Sized by |
|---|---|
| Box | Half extents: half its size along each axis. |
| Sphere | Radius |
| Capsule, Cylinder | Radius and Half height |
| ConvexMesh | A Mesh, wrapped tight like shrink wrap. Fast, good for most props. |
| TriangleMesh | A Mesh, exactly. Use it for static scenery with hollows and overhangs. |
The object’s scale scales the collider too.
Friction is how much a surface grips (0 is ice), Restitution how much it bounces (0 is a dead stop, 1 bounces back as fast as it came). Friction combine and Restitution combine say how two colliders’ values combine when they touch: Average, Min, Multiply or Max. Density is used to work out mass for shapes on a body.
Collisions and triggers
When two colliders start touching, every script on both objects gets
on_collision(other, normal), and on_collision_exit(other) when they part.
Turn on Sensor and the collider stops blocking things. It reports
overlaps instead, with on_trigger_enter(other) and on_trigger_exit(other):
a pickup, a checkpoint, a door’s “someone is near” zone.
fn on_trigger_enter(other) {
if other.name == "Player" {
other.send("take_key")
Scene.destroy()
}
}
See Hooks and events.
Collision layers
Every collider is in some layers and collides with some layers: Collision groups is which ones it’s in, Collision mask which ones it hits. Two colliders touch only when each is in a layer the other’s mask includes. Both are 32-bit masks, one bit per layer, and by default a collider is in every layer and hits every layer.
In the Inspector both are numbers: add up the values of the layers you want.
Layer 0 is 1, layer 1 is 2, layer 2 is 4, layer 3 is 8, and so on, doubling.
So a collider in layer 1 that hits only layers 0 and 2 has groups 2 and mask
5. 4294967295, the default, is every layer.
You can name the 32 layers in File → Project Settings → Collision to keep track of what each is for. For now the names are a note for you: the Collider still shows numbers.
Characters
A player that walks, climbs stairs and slides along walls is fiddly to build from a dynamic body. A Character Controller does it for you: give the object a capsule Collider and a Character Controller, then set its velocity from a script each frame.
fn on_update(delta: float) {
var h = Input.axis("horizontal")
var v = Input.axis("vertical")
// Keep the vertical speed, so gravity still pulls.
self.get_component("CharacterController").set_velocity(Vec3(h * 6.0, self.velocity.y, -v * 6.0))
}
self.grounded says whether it’s standing on something. Slope limit is
the steepest floor it can walk up, Step height the tallest ledge it steps
over, and Mass how hard it shoves dynamic bodies it walks into.
Joints
A joint ties a body to another one, named in Connected body. Anchor and Connected anchor are where it attaches on each, in each body’s own space.
| Joint | What it does |
|---|---|
| Fixed Joint | Glues the two together. |
| Hinge Joint | Lets them turn about one Axis, like a door. Limits stops it between Min angle and Max angle (degrees); Motor turns it at Motor speed. |
| Spring Joint | Pulls them toward Rest length apart, with Stiffness and Damping. |
Pushing things from scripts
These are actions of the Rigid Body, so they are called on the component, not on
self:
fn on_update(delta: float) {
var body = self.get_component("RigidBody")
body.apply_force(Vec3(0, 0, -20)) // a steady push: call it every frame
}
fn kick() {
self.get_component("RigidBody").apply_impulse(Vec3.up * 5.0) // changes the velocity at once
}
apply_force and apply_torque push for the next physics step only.
apply_impulse and apply_torque_impulse are kicks, and set_velocity and
set_angular_velocity set the speed outright. Scene.raycast(from, direction, distance) says what a ray hits first. They are all listed in the Cog API
reference.