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 typeWhat it isExamples
DynamicMoved by physics: falls, bounces, gets pushed.Crates, balls, ragdolls, the Skyhawk aircraft
StaticNever moves.Floors, walls, terrain
KinematicMoved 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

ShapeSized by
BoxHalf extents: half its size along each axis.
SphereRadius
Capsule, CylinderRadius and Half height
ConvexMeshA Mesh, wrapped tight like shrink wrap. Fast, good for most props.
TriangleMeshA 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.

JointWhat it does
Fixed JointGlues the two together.
Hinge JointLets 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 JointPulls 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.