Raycast filtering by collision layers (#158): Colliders gained the "Layers" setting of the Raycast node with the one-sided rule - a ray is not a collider and never reads the collidesWith of what it hits - and the note that a running behavior instance keeps the graph it started with; Physics lost the line that a layer filter for rays comes later and names #157 as the only open point; Behaviors describes the node; Development carries the check sum 1153
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent
cf23b4ac5d
commit
bc2a138c8c
4 files changed
+37
-28
No files matched your search
+1
-1
@@ -116,7 +116,7 @@ shown on the node and editable in the inspector.
|
|||||||
behavior that started it unless `detached` says otherwise),
|
behavior that started it unless `detached` says otherwise),
|
||||||
`Load scene` (swaps the running scene once the frame is over — see [Scenes](Scenes)), `Log`, `Stop game`, `Restart game`,
|
`Load scene` (swaps the running scene once the frame is over — see [Scenes](Scenes)), `Log`, `Stop game`, `Restart game`,
|
||||||
`Apply force`, `Apply impulse`, `Set velocity`, `Set angular velocity`, `Set gravity` (see [Physics](Physics)),
|
`Apply force`, `Apply impulse`, `Set velocity`, `Set angular velocity`, `Set gravity` (see [Physics](Physics)),
|
||||||
`Raycast` (what a ray meets first: object, collider, point, normal, distance — see [Colliders](Colliders#raycast)),
|
`Raycast` (what a ray meets first on the layers it looks at: object, collider, point, normal, distance — see [Colliders](Colliders#raycast)),
|
||||||
`Ignore one-way` (fall through one-way colliders and tiles for some seconds — see [Colliders](Colliders#one-way)). A node type is one file exporting a `NodeDef`
|
`Ignore one-way` (fall through one-way colliders and tiles for some seconds — see [Colliders](Colliders#one-way)). A node type is one file exporting a `NodeDef`
|
||||||
(ports, settings, `run`), listed in `nodes/index.ts`; palette, ports, validation and
|
(ports, settings, `run`), listed in `nodes/index.ts`; palette, ports, validation and
|
||||||
inspector fields are generated from it. A port may declare a `default` for its inline value
|
inspector fields are generated from it. A port may declare a `default` for its inline value
|
||||||
|
|||||||
+19
-11
@@ -1,12 +1,12 @@
|
|||||||
A **collider** is an asset (`shape` box, circle, capsule or polygon – see
|
A **collider** is an asset (`shape` box, circle, capsule or polygon — see
|
||||||
[Shapes](#shapes)) placed like any
|
[Shapes](#shapes)) placed like any
|
||||||
other object — typically as a child of the sprite it belongs to, so its position is the offset
|
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** → *Add
|
from that *body* and it moves with it. Right-click an object in **Scene objects** → *Add
|
||||||
collider* to get one with one click: a box collider sized like the
|
collider* to get one with one click: a box collider sized like the
|
||||||
sprite, parented at its centre. Colliders can be reused across objects, overridden per instance
|
sprite, parented at its centre. Colliders can be reused across objects, overridden per instance
|
||||||
and stacked (hitbox + hurtbox on one sprite; colliders of the same body never collide with each
|
and stacked (hitbox + hurtbox on one sprite; colliders of the same body never collide with each
|
||||||
other). They are editor symbols: green outlines in edit mode, invisible in play mode. Three more rows –
|
other). They are editor symbols: green outlines in edit mode, invisible in play mode. Three more rows —
|
||||||
friction, bounciness, density – are the material a rigidbody feels (see [Physics](Physics)).
|
friction, bounciness, density — are the material a rigidbody feels (see [Physics](Physics)).
|
||||||
|
|
||||||
A collider takes the transform of its body: a box turns and grows with the sprite it sits on, a
|
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](Scene-editing)). A turned box is tested as the
|
circle grows (see *Transform* in [Scene editing](Scene-editing)). A turned box is tested as the
|
||||||
@@ -15,15 +15,15 @@ its slant.
|
|||||||
|
|
||||||
## Shapes
|
## Shapes
|
||||||
|
|
||||||
- **Box** – `width` × `height`.
|
- **Box** — `width` × `height`.
|
||||||
- **Circle** – `radius`.
|
- **Circle** — `radius`.
|
||||||
- **Capsule** (#151) – fills `width` × `height` and is rounded along the longer side: its radius is
|
- **Capsule** (#151) — fills `width` × `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
|
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.
|
over edges instead of catching on them.
|
||||||
- **Polygon** (#151) – `points`, a list of `{x, y}` corners in the collider's own units, so they
|
- **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
|
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: **drag** a corner to move it, **press on an
|
selected in the scene view every corner has a handle: **drag** a corner to move it, **press on an
|
||||||
edge** to put a corner there (and drag it on), **double-click** a corner to take it away – three
|
edge** to put a corner there (and drag it on), **double-click** a corner to take it away — three
|
||||||
corners always stay. Each is one undo step. The list can also be edited in the inspector.
|
corners always stay. Each is one undo step. The list can also be edited in the inspector.
|
||||||
A polygon may be concave: it is cut into convex pieces (ear clipping, then the cuts that are not
|
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
|
needed are joined again), which is what collision works with. One that crosses itself or has no
|
||||||
@@ -33,7 +33,7 @@ Box against box, circle against circle and box against circle keep their own exa
|
|||||||
pair with a capsule or a polygon goes one common way (`core/properties/convex.ts`): each shape is a
|
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
|
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
|
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.
|
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;
|
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
|
touching edges do not count) into *enter*, *stay* and *exit*. While playing that is the physics
|
||||||
@@ -59,7 +59,7 @@ colliders, a tile counts 0.5). The contact's normal decides which way "along" is
|
|||||||
runs into an edge rolls up over it, an object pressed onto a slope slides down it unless the pair
|
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
|
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
|
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
|
between floor and wall is two). There is no bounce: `Move` sets a distance, not a speed — a
|
||||||
dynamic body bounces (see [Physics](Physics)). The outputs: `blocked x` / `blocked y` tell which of
|
dynamic body bounces (see [Physics](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
|
the object's own axes something stood against (a floor blocks y, a wall x, a slope each axis the
|
||||||
move went along);
|
move went along);
|
||||||
@@ -135,6 +135,11 @@ check, a laser, a hitscan shot.
|
|||||||
|
|
||||||
- Met are solid colliders of every shape and the cells of a tilemap, outlined ones too. Triggers
|
- 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.
|
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
|
- 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
|
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.
|
figure finds what is around it; one starting on an outline and running in meets it at 0.
|
||||||
@@ -144,4 +149,7 @@ check, a laser, a hitscan shot.
|
|||||||
everything is right now — not about the last physics step.
|
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
|
- 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.
|
where it met something, grey to its end when it met nothing.
|
||||||
- Only the first hit for now; a list of all hits and a filter by collision layer (#152) come later.
|
- Only the first hit for now; a list of all hits (#157) comes later.
|
||||||
|
- A setting reaches a *running* instance only when that instance starts afresh: the interpreter
|
||||||
|
holds the graph it began with, so a behavior that already runs in the editor keeps casting with
|
||||||
|
the layers it started on until it is switched off and on (or Play is pressed).
|
||||||
+1
-1
@@ -13,7 +13,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
|
|||||||
npm run build # writes dist/ and regenerates index.html
|
npm run build # writes dist/ and regenerates index.html
|
||||||
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
|
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
|
||||||
php tools/make-user.php <name> <password> # an account; every tool signs in (see Accounts)
|
php tools/make-user.php <name> <password> # an account; every tool signs in (see Accounts)
|
||||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1148 editor checks, screenshots in /tmp/gm-e2e-*.png
|
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1153 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||||
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
|
GM_STEPS=20 node tools/e2e.mjs # or 1-12, or 6,20 — a subset while working on one step
|
||||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||||
./e2e.sh status # live progress, or the last run's result
|
./e2e.sh status # live progress, or the last run's result
|
||||||
|
|||||||
+16
-15
@@ -1,6 +1,6 @@
|
|||||||
Play simulates **rigidbodies** on the physics engine [Rapier 2D](https://rapier.rs) (#146): they
|
Play simulates **rigidbodies** on the physics engine [Rapier 2D](https://rapier.rs) (#146): they
|
||||||
fall, slide, bounce, tip over and come to rest. What has no rigidbody behaves exactly as it did
|
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.
|
before the engine — see *Without a rigidbody* below.
|
||||||
|
|
||||||
## The rigidbody
|
## The rigidbody
|
||||||
|
|
||||||
@@ -13,13 +13,13 @@ edit mode and not at all in the game. Its rows:
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 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. |
|
| 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. |
|
| 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. |
|
| 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. |
|
| Linear damping | 0 | Slows the movement down by itself, like air. |
|
||||||
| Angular damping | 0 | The same for turning. |
|
| 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. |
|
| 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. |
|
| 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
|
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
|
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
|
switched off is as if it were not there. A body without any solid collider still falls, with its
|
||||||
mass or 1 kg.
|
mass or 1 kg.
|
||||||
@@ -45,7 +45,7 @@ A trigger (`isTrigger`) weighs nothing and never pushes; it only reports.
|
|||||||
|
|
||||||
A capsule collider is the engine's capsule; a polygon is one convex polygon per piece it is cut
|
A capsule collider is the engine's capsule; a polygon is one convex polygon per piece it is cut
|
||||||
into (see [Colliders](Colliders#shapes)), all on the same body, so a concave shape rests and rolls
|
into (see [Colliders](Colliders#shapes)), 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
|
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
|
notch. A rigidbody's fixed **Mass** is shared out among the pieces by area, and density weighs each
|
||||||
by its own area.
|
by its own area.
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ It is read every frame, so an animation over the scene can change it while playi
|
|||||||
The engine steps at a fixed **60 steps per second**, whatever the frames take; a frame that took
|
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
|
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,
|
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
|
so it moves evenly on any display — which also means it is drawn up to one step (1/60 s) behind the
|
||||||
engine.
|
engine.
|
||||||
|
|
||||||
## Collision events
|
## Collision events
|
||||||
@@ -81,17 +81,17 @@ made in the same frame.
|
|||||||
|
|
||||||
An object with colliders but no rigidbody is what every project was before: its colliders go
|
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.
|
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
|
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
|
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](Tilemaps)). `Move` with
|
static ground made of its merged solid cells (see [Tilemaps](Tilemaps)). `Move` with
|
||||||
*Collide with solids* works as described in [Colliders](Colliders): the object stops flush at what
|
*Collide with solids* works as described in [Colliders](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
|
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.
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
dynamic mover what the engine says. The mover stays flush in front of the crate and never gets
|
||||||
@@ -152,7 +152,7 @@ first time the console points to the nodes above, which move it with the physics
|
|||||||
## Play and the editor run
|
## Play and the editor run
|
||||||
|
|
||||||
The editor loads the engine right after opening the project; Play waits for it if it is not there
|
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
|
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
|
the console say why. There is no falling back to the old detection: a game would collide
|
||||||
differently.
|
differently.
|
||||||
|
|
||||||
@@ -161,11 +161,12 @@ are placed, because what the editor run moves is saved. The nodes above do nothi
|
|||||||
|
|
||||||
## What is not there yet
|
## What is not there yet
|
||||||
|
|
||||||
- `Move` stepping up onto a ledge, or a limit on how steep a slope it walks up – that is for the
|
- `Move` stepping up onto a ledge, or a limit on how steep a slope it walks up — that is for the
|
||||||
graph, with `hit` and `normal` (#150). `Move` does not use Rapier's character controller: in #147
|
graph, with `hit` and `normal` (#150). `Move` does 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
|
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; `Move` works out its contacts itself,
|
crates), kept a gap of up to 1.7 units and knows no friction; `Move` works out its contacts itself,
|
||||||
in double precision, and slides over the same seams without catching (#150).
|
in double precision, and slides over the same seams without catching (#150).
|
||||||
- The simulation in the editor run (#148).
|
- The simulation in the editor run (#148).
|
||||||
- Joints (#154), and a ray filtered by collision layers (#158). Raycasts (#153), one-way platforms
|
- Joints (#154), and "Raycast all" as a list of every hit (#157). Raycasts (#153) with their layer
|
||||||
(#155) and the collision layers themselves (#152) are there, see [Colliders](Colliders#raycast).
|
filter (#158), one-way platforms (#155) and the collision layers themselves (#152) are there,
|
||||||
|
see [Colliders](Colliders#raycast).
|
||||||
Reference in new issue
Block a user