World & physics
Create discs, walls, goals and lines in the physical world of a running match.
During a match, your game has a physical world: the ball, the players' discs, the walls, the goals. You create these objects and set their properties; disko moves them, makes them bounce off each other, and tells you when something interesting happens.
You never write the physics yourself. There's no "move the ball by its velocity" or "check if two circles overlap" in a disko game. That work is done by disko, the same way on every player's screen.
When the world exists
The world belongs to a match. It's created when a match starts and thrown
away when it stops, so you build your field in the start handler. The
world global is only usable between start and stop; using an object
after its match ended throws a StaleHandleError.
What happens in one tick
A running match advances in ticks, 60 per second. In each tick, disko applies the players' inputs, runs your code, moves everything, and then tells you what happened:
tickruns before the physics step: a good place to change velocities or rules for this tick.post-tickruns after it, along withcrossingand sensor events: a good place to react to where things ended up, such as a goal.
Both handlers receive the tick number and the events of that turn, in the order they were delivered.
The objects
| Create with | Object | What it's for |
|---|---|---|
world.createDisc | Disc | balls and player discs |
world.createPlane | Plane | infinite straight walls |
world.createVertex | Vertex | fixed points, and the ends of segments |
world.createSegment | Segment | straight or curved walls between two vertices |
world.createJoint | Joint | keeping two discs at a distance |
world.crossing | Crossing | lines that report discs crossing them |
world.visual | Visual | labels and rings that don't collide |
This builds a small field: four walls, a ball, a goal post and a goal line.
Every object has setters for its properties, such as disc.setVelocity,
disc.setMass or segment.setCurve. state() returns where an object is and
how it's moving at the current tick; a disc's DiscState has its position,
velocity, radius and collision properties. world.destroy(object) removes an
object.
How a disc looks
disc.setAppearance({ fill, stroke, strokeWidth }) sets a disc's colors:
#rrggbb or #rrggbbaa colors and an outline from 0 to 64 CSS pixels wide
(0 hides it). All three are required. A new disc is #f5f7fb with a black
2-pixel outline. For an image instead of a color, see
Assets.
Who collides with what
Not everything should bump into everything. In football, players shouldn't walk into the goal net, but the ball should bounce off it.
That's what collision groups are for. Each object belongs to groups
(addGroup, removeGroup) and lists the groups it collides with
(setAcceptedGroups). Two objects only collide if each accepts the other.
Some objects shouldn't collide at all, only notice contact:
A sensor reports
sensor-enterandsensor-leaveinstead of bouncing, for example to detect a player standing in an area.A crossing is a line that reports discs passing through it. It never blocks anything, which makes it the natural goal line. It has groups too, so it can ignore players and only watch the ball.
Every collidable object also has a restitution: how bouncy its collisions are, from 0 (dead stop) to 1 (no energy lost).
Reacting to crossings
crossing fires when a disc crosses a crossing line. It tells you which disc
(object), which way (forward or backward), where, and the fraction of
the tick's movement at which the crossing happened. This resets the ball when
it crosses forward:
Ending a match
stop reports the final tick and why the match ended: finished after your
game calls game.finish(), or stopped when the room stopped it.
Visuals
Visuals are drawings with no physical presence, such as a name above a player
or a ring under the disc you control. world.visual({ anchor, appearance, audience })
attaches a text label or a ring to a disc or a position, and audience
chooses which players see it. visual.update(patch) changes it and
visual.destroy() removes it.
See the world reference for every option.