26
Colliders
meleki edited this page 2026-10-02 23:53:00 +02:00

A collider is an asset (shape box, circle, capsule, polygon or frame collision — see Shapes) placed like any other object — typically as a child of the sprite it belongs to, so its position is the offset from that body and it moves with it. Right-click an object in Scene objects (or in the scene view) → Add collider…: a second menu offers Create new collider — a box collider sized like the sprite, parented at its centre — and below it every collider of the project, with a search field on top (#222). Picking one places that asset as it is, no copy made; a collider the object wears already is greyed out. Colliders can be reused across objects that way, overridden per instance and stacked (hitbox + hurtbox on one sprite; colliders of the same body never collide with each other).

On a sprite whose picture is a frame with a collision outline, the new collider is a Frame collision of that frame instead of a box (#218). It reads the frame the sprite shows at that moment, an animation changing the frame later does not change the collider. A sprite drawn bigger or smaller than the frame gets the collider's Scale set so the outline covers the picture. A sprite stretched out of the frame's proportions keeps the box, because an outline cannot be stretched; so does a frame without an outline, a whole texture or vector art.

Fit to sprite (#222) in the menu of a placed collider sizes it like the sprite it sits on and centres it there — handy after the sprite changed size or the collider was dragged aside. The size goes into this placement's overrides, so other sprites wearing the same collider keep theirs; a value equal to the asset's own clears the override instead. The collider's own scale is divided out, a collider turned by a quarter swaps width and height, and a circle takes the radius that fits inside. A polygon or frame outline has no size to fit, and a collider that does not sit on a sprite has nothing to fit to: the entry is greyed out for both. They are editor symbols: green outlines in edit mode, invisible in play mode. Like every other symbol a collider also has an icon, white in a dark outline like all of them. It stands on the collider's centre unless another icon wants the same spot, and a click on it selects the collider, just like a click on its outline. With a rigidbody on the same body the two icons stand left and right of the centre (see Scene editing). Three more rows — friction, bounciness, density — are the material a rigidbody feels (see Physics).

A collider takes the transform of its body: a box turns and grows with the sprite it sits on, a circle grows (see Transform in Scene editing). A turned box is tested as the box it is — separating axes, not its upright frame — so a wall turned by 45 degrees blocks along its slant.

Shapes

  • Box — width x height.
  • Circle — radius.
  • Capsule (#151) — fills width x height and is rounded along the longer side: its radius is half the shorter side. As wide as tall it is a circle. The shape for a figure that should slide over edges instead of catching on them.
  • Polygon (#151) — points, a list of {x, y} corners in the collider's own units, so they turn, grow and mirror with the object. A new polygon collider is a triangle. With the collider selected in the scene view every corner has a handle. Click a corner to pick it (drawn filled) and drag it to move it. Double-click an edge to put a corner there; it is picked and stays in place until it is pressed again. Delete takes the picked corner away and leaves the collider — without a picked corner Delete removes the object, as everywhere. A right-click on a corner opens a menu with Delete point. Three corners always stay. The pick ends with a press beside the corners and when another object is selected. Each change is one undo step. The inspector does not list the corners (#295): the outline in the scene view is where they are edited. A polygon may be concave: it is cut into convex pieces (ear clipping, then the cuts that are not needed are joined again), which is what collision works with. One that crosses itself or has no area is drawn red and collides with nothing.
  • Frame collision (#193) — wears the collision outlines of a texture frame, the ones drawn in the Texture tab for tiles (see Textures). The Frame row picks the frame like a sprite's texture. The collider stays linked: redraw the outline and every collider wearing that frame blocks with the new one, in the editor and in the next Play. The frame is centred on the collider's origin, one image pixel to one unit, so a collider on a sprite of that frame at its own size lies exactly over the picture. It turns, grows and mirrors with the object like any shape. A frame with several outlines blocks with all of them, each cut into convex pieces like a polygon. The corners are edited in the Texture tab, not in the scene view. Without a frame, with a whole texture instead of a frame, or on a frame nobody outlined, the collider is drawn red as a box and collides with nothing: the frame's box when there is one, else its own width x height.

Box against box, circle against circle and box against circle keep their own exact tests. Every pair with a capsule or a polygon goes one common way (core/properties/convex.ts): each shape is a set of convex pieces, each piece a point, a segment or a polygon grown by a radius, and two pieces are tested along their separating axes, apart by their real distance. A square polygon meets everything exactly as the box it stands for — a unit test holds the two against each other.

Before the behaviors, every frame sorts the colliders that overlap (world transforms applied; touching edges do not count) into enter, stay and exit. While playing that is the physics engine's work (PhysicsSystem, see Physics), which also simulates rigidbodies; the editor run tests all pairs itself (CollisionSystem) and pushes nothing. Without a rigidbody both come to the same answer. A behavior receives On collision enter/stay/exit for the colliders of its owner (its parent; itself when top-level): the outputs are other (the other body), other collider and collider (the own one); while playing, On collision enter and On collision stay also tell the direction, the strength and the point of the contact (see Physics). On collision stay fires every frame by default; with an Interval (s) above 0 it fires once each time that long has passed since the pair met, on a clock of its own per pair that starts over when they meet again (#149). On a trigger tile of a tilemap the three events also tell the tile and its cell x and cell y, once per area of the tile or, with the input per cell, once per cell (see Tilemaps). Is touching(a, b) answers the same question on demand — an object stands for its collider children, a collider for itself. The geometry lives in src/core/properties/collider.ts so editor and runtime agree on it.

Blocking is opt-in per movement: the Move node has a Collide with solids setting (default off). When enabled the object's solid colliders move along (dx, dy) — in its own axes, which a turned parent turns as well — until one runs into a solid collider; there the object stops flush (exitDistance in collider.ts: the travel at which the shapes stop overlapping). What is left of the move then goes on along the surface: the part into it is dropped, and the part along it is shortened by friction times the part into it (Coulomb; the pair's friction is the average of both colliders, a solid tile brings its own, see Physics). The contact's normal decides which way "along" is, so a circle that runs into an edge rolls up over it, an object pressed onto a slope slides down it unless the pair is rough enough to hold it (friction ≥ tan of the slope), and one pressed against a wall slides along it the slower the harder it presses. Up to four contacts are followed per move (a corner between floor and wall is two). There is no bounce: Move sets a distance, not a speed — a dynamic body bounces (see Physics). The outputs: blocked x / blocked y tell which of the object's own axes something stood against (a floor blocks y, a wall x, a slope each axis the move went along); hit whether anything was met; normal x / normal y which way the first surface faces, in the world, pointing away from it (where a corner meets a corner of a capsule or polygon, any direction between the two faces is right; the one taken is the one that stands least in the move's way, so a figure walking into the foot of a slope climbs it) — enough to build a bounce or a wall jump in the graph. All are false / 0 with the setting off. An object without a solid collider of its own moves freely. In Play a dynamic body that stops the move is pushed into the contact (see Physics). A collider with Trigger (no blocking) enabled (isTrigger, drawn amber instead of green) still produces collision events but never blocks. An overlap that already exists is never resolved (no jolt when objects start stacked or inside a wall) but also never deepened, so such an object can always leave. A move longer than the thinnest collider involved is split into sub-steps — a fast object cannot jump across a thin wall and end up on the other side. Colliders of the moving object and of anything parented under it travel with it and cannot block it. Move without the setting and Set position ignore colliders entirely.

Before any of that is worked out exactly, the move is measured against a rectangle around each of its colliders, grown by the length of the whole move (#184): what lies outside it cannot be met, because sliding never lengthens what is left of a move, so the object never gets farther from where it starts than the move is long. Only what that rectangle touches is turned into shapes and tested; the same rectangle drops what sits on a layer the mover does not meet. A ray does the same with the rectangle around itself. This changes no result — it decides nothing, it only leaves out what could not have been reached — but it is what keeps a map of outlined cells from costing a frame (see Tilemaps).

One-way

A collider with One-way on (#155) blocks only what comes from one side: Blocks from says which — Above by default, or Below, Left, Right — in the collider's own axes, so it turns and mirrors with its object. In the scene view that side is drawn thick, with a fan on its middle showing the One-way angle. It is the platform a figure jumps through from below and lands on from above:

  • It blocks a contact whose normal lies within the One-way angle of that side — 45 degrees by default, 0 to 90 (#159); anything else passes - from below, and from the side as well, as in Unity and Godot. The angle counts where the surface is not square to that side: on a slope of 25 degrees in a polygon blocking from Above, a figure lands at 25 degrees or more and falls through below that. At 90 degrees the sides block too, only what comes from the opposite side passes.
  • Blocks from and One-way angle show in the inspector only while One-way is on.
  • What is already inside it passes on through for as long as it is inside, so a jump that did not clear the top falls back out below.
  • Move with Collide with solids reports hit only where it was stopped, and a fast fall is still caught: the move is swept in steps no thicker than the platform.
  • Ignore one-way (object, seconds, 0.25 by default) lets the object fall through all one-way colliders and tiles for that long — drop down with the down key. When the time is up it still passes what it is inside and lands on the next one it comes down on.
  • A dynamic body lands, passes and drops the same way (see Physics).
  • A ray meets it only from the side it blocks from.

Tiles can be one-way as well (see Tilemaps).

Collision layers

A project has up to 16 named collision layers (#152), edited in the top bar's menu → Project settings…; a new project has one, Default. Every collider and every tilemap names the layer it sits on (Layer) and the layers it collides with (Collides with, a tick per layer).

Two things meet only when each one names the layer of the other. The rule is symmetric, as in the physics engine itself, so there is no pair that collides only one way: giving the player's shots their own layer and leaving the player out of their Collides with is enough — the player does not have to be changed as well, but the shots have to name what they should hit.

  • The default is layer 0 against every layer, which is what every collider written before there were layers reads as. Nothing collides differently until a layer is named.
  • One setting decides both: what does not collide reports no event either. To be notified without being blocked, use Trigger (no blocking).
  • It filters everything alike — the engine in Play, Move with Collide with solids, and the collision events of the editor run.
  • A ray has a filter of its own, Layers on the Raycast node (see below).
  • Only the last layer can be removed in the dialog: a collider names its layer by number, so taking one out of the middle would move every collider below it onto another layer.

Changing the layer while the game runs

A behavior changes both settings with a Properties node of type Collider (#211): add layer or collidesWith under + Property, switch the port to Set, and the node shows the same picker as the inspector — the project's layers by name, or a tick per layer. For a figure that is invulnerable for a moment, a ghost that walks through walls, a carried crate that stops blocking.

  • The node takes the collider itself, not the object it sits on: Child by name of the owner, or the collider output of a collision event or of Raycast.
  • It holds from the next Move, the next ray and the next physics step on, in the editor run and in Play alike. A dynamic body resting on ground it no longer meets starts to fall.
  • A pair that still meets after the change reports no new enter or exit.
  • Read the same way, layer is the number of the layer (0 for the first), not its name.
  • Layer of gives the name: it takes an object and answers name (as the project calls the layer) and number. An object stands for its first collider child, switched on or not; a collider or tilemap for itself. Without a collider the name is empty and the number -1. It answers at the moment it is asked, so right after a Set in the same flow it already names the new layer. Feed name into Equals to branch on the layer.
  • Like every change a graph makes, it lasts for the run in Play; the editor run writes it into the scene.

Raycast

The Raycast node (#153) casts a ray from from x/y along dir x/y (any length, it is made a unit vector) for up to length world units, and says what it meets first: hit, the object (the body, like other of a collision), its collider (or the tilemap), the point x/y, the normal x/y of the face (pointing out of it) and the distance. For line of sight, a ground check, a laser, a hitscan shot.

  • Met are solid colliders of every shape and the cells of a tilemap, outlined ones too. Triggers only with Hit triggers on. A one-way collider or tile only from the side it blocks from.
  • Layers (#158) is a tick per collision layer of the project, all of them ticked to begin with: the ray only meets what sits on one of the ticked layers. That is the one place where the layers are not symmetric — a ray is not a collider, so what it may look at is its own business and a collider's "Collides with" has no say in it. A shot that passes friends is Layers without their layer; a ground check that ignores the water is the same thing one layer over.
  • With Ignore owner on (the default) the behavior's owner and everything parented below it are not met. And a shape the ray starts inside is never met — so a ray cast from the middle of a figure finds what is around it; one starting on an outline and running in meets it at 0.
  • Grazing a corner counts as meeting it.
  • It is worked out in our own double-precision geometry (core/properties/ray.ts) over the same shapes Move collides with, so the editor run and Play answer alike, and always about where everything is right now — not about the last physics step.
  • In the editor run every ray cast shows in the scene view for a quarter of a second: green to where it met something, grey to its end when it met nothing.
  • Raycast says what it meets first; Raycast all (below) says everything on the line.
  • A setting changed while the behavior runs in the editor is what the next cast uses (see Editing the graph while it runs in Concepts).

Raycast all

The Raycast all node (#157) casts the same ray and hands back everything it meets, for a shot that goes through several enemies, a laser, or "what is on this line". It takes the same inputs and the same settings as Raycast — Ignore owner, Hit triggers, Layers — plus max hits.

  • The answer is parallel lists, sorted by distance: objects, colliders, points x, points y, normals x, normals y, distances, and the plain number count. Item n of every list belongs to the same hit, so Item at with one index reads a whole hit out of them. Lists rather than a run of the flow per hit: that is what Count, Item at and Sub list already work with.
  • objects and colliders hold live objects, not names — Item at gives one back as an object, ready for Destroy, Apply force or Name of. Written into a list variable they stay objects for the rest of the run; only what leaves the run (a save, the scene) holds the empty object instead, see Behaviors.
  • A collider counts once, however many convex pieces its shape falls into, and the hit is the first face the ray enters. A tilemap counts once per cell the ray goes through, since a map is many solids under one entity — the collider of each of those hits is the tilemap.
  • max hits above 0 keeps that many of the nearest and leaves the rest out; 0 (the default) keeps all of them.
  • In the editor run the ray is drawn to the last thing it met — that is how far it looked.