Physics stage 1b: Moving bodies from a graph and pushing with Move in Physics, the new nodes in Behaviors, blocking in Colliders, Architecture, check total 1055 (#147)
1 parent
f6904445d8
commit
d6190ec3ee
5 files changed
+42
-10
No files matched your search
+2
-1
@@ -86,7 +86,8 @@ src/runtime/ World, Entity, System interface, Input tracker, Collision
|
||||
Audio (the AudioSink a run plays into — the counterpart of Input on the way out)
|
||||
src/runtime/physics/ engine (loads Rapier once, reports its state, converts between pixels and metres),
|
||||
PhysicsSystem (Play's collisions: one engine body per rigidbody, free collider and tilemap,
|
||||
the fixed step, the poses handed back, the contact pairs sorted into events)
|
||||
the fixed step, the poses handed back, the contact pairs sorted into events; the push a
|
||||
`Move` gives a dynamic body, and what the physics nodes reach through `NodeContext.physics`)
|
||||
src/ui/ widget toolkit (generic, knows nothing about assets)
|
||||
src/viewport/ view (transforms), items (what to draw), symbols (how to draw it),
|
||||
FileLibrary (load once, never retry a failure, tell the listeners) ← TextureLibrary, FontLibrary;
|
||||
|
||||
+3
-2
@@ -107,14 +107,15 @@ shown on the node and editable in the inspector.
|
||||
`Join lists`, `Index of`, structs `Pack`/`Expand`,
|
||||
`Length`, `Distance`, `Normalize`, `Axis input` (four keys → a
|
||||
normalized direction, so diagonals are not faster), `Compare`, `And/Or/Not`, `Key is down`,
|
||||
`Mouse position`, `Mouse button`, `Is hovered`, `Is touching`, `Current state` (name and id), `Is in state` (one boolean per state) ·
|
||||
`Mouse position`, `Mouse button`, `Is hovered`, `Is touching`, `Get velocity`, `Current state` (name and id), `Is in state` (one boolean per state) ·
|
||||
actions `Move` (dx, dy, scale, dt — connect an event's dt for per-second movement; in the object's own axes, which a turned parent turns too), `Set position`, `Spawn`
|
||||
(asset setting + x/y/z, optional parent → outputs the new object), `Destroy`, `Emit` (starts a particle source over, see *Particles*),
|
||||
`Play sound` / `Stop sound` (see [Sounds](Sounds): the asset says how loud and whether it loops, the node's
|
||||
`volume` multiplies that and its `loop` either leaves it alone or overrules it in either
|
||||
direction; every play is a voice of its own, so two in a row overlap, and the voice ends with the
|
||||
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`. A node type is one file exporting a `NodeDef`
|
||||
`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)). A node type is one file exporting a `NodeDef`
|
||||
(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
|
||||
(e.g. `Move.scale = 1`), shown on the node and in the inspector.
|
||||
|
||||
+2
-1
@@ -28,7 +28,8 @@ object stands for its collider children, a collider for itself. The geometry liv
|
||||
parent turns as well — and, after each axis, pushes its *solid* colliders back along that axis to
|
||||
just touch any solid collider they ran into (`exitDistance` in `collider.ts`: the travel at which
|
||||
the shapes stop overlapping) — so the other axis still moves and the object slides along walls. Its `blocked x` / `blocked y` outputs tell which
|
||||
axes hit (always `false` with the setting off). A collider with
|
||||
axes hit (always `false` with the setting off). In Play a dynamic body that stops the move is pushed
|
||||
along (see [Physics](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
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ npm run check # typecheck + lint + format:check + tests, the gate CI runs
|
||||
# code is lost (tail's is reported), so a red run reads as green
|
||||
npm run build # writes dist/ and regenerates index.html
|
||||
./build.sh # the same under `set -o pipefail`, for callers that pipe the output
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1052 editor checks, screenshots in /tmp/gm-e2e-*.png
|
||||
node tools/seed-e2e.mjs && node tools/e2e.mjs # 1055 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
|
||||
./e2e.sh start [GM_STEPS] # the same run detached, see below
|
||||
./e2e.sh status # live progress, or the last run's result
|
||||
|
||||
+34
-5
@@ -68,8 +68,35 @@ wherever the object is put, nothing pulls on them, and dynamic bodies bounce off
|
||||
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
|
||||
static ground made of its merged solid cells (see [Tilemaps](Tilemaps)). `Move` with
|
||||
*Collide with solids* works as described in [Colliders](Colliders); a dynamic body blocks it like a
|
||||
wall.
|
||||
*Collide with solids* works as described in [Colliders](Colliders): the object stops flush at what
|
||||
is in its way and slides along it.
|
||||
|
||||
A dynamic body that stops such a move gets **pushed** 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
|
||||
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
|
||||
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
|
||||
into it.
|
||||
|
||||
## Moving bodies from a graph
|
||||
|
||||
| Node | What it does |
|
||||
|---|---|
|
||||
| **Apply force** | Pushes with a force (units × kg per second²) for the length of the frame, so from `On update` it pushes steadily at any frame rate. A heavier body speeds up less. |
|
||||
| **Apply impulse** | A kick at once (units × kg per second): the velocity changes by impulse ÷ mass. A jump, a hit, an explosion. |
|
||||
| **Set velocity** | Sets the speed in units per second, whatever the body weighs. For one direction only, feed the other from `Get velocity`. |
|
||||
| **Set angular velocity** | Sets the turning speed in degrees per second, counted like the rotation. A body with *Fixed rotation* does not turn, and does not start to later either. |
|
||||
| **Get velocity** | Speed (x, y) and turning speed (degrees/s); 0 for an object without a dynamic body. |
|
||||
| **Set gravity** | The scene's gravity for the rest of the run; the next scene starts with its own, and the project keeps its value. |
|
||||
|
||||
The object is the one the rigidbody sits on (the rigidbody itself works too). They act on a
|
||||
**dynamic** body only; on anything else they do nothing, and the console says so once per object:
|
||||
`Physics: "Player" has no dynamic rigidbody, so Apply force, Apply impulse and Set velocity do
|
||||
nothing on it.` They work from `On start` on.
|
||||
|
||||
`Move` and `Set position` on a dynamic body put it somewhere else and it keeps its velocity; the
|
||||
first time the console points to the nodes above, which move it with the physics.
|
||||
|
||||
## Play and the editor run
|
||||
|
||||
@@ -79,11 +106,13 @@ the console say why. There is no falling back to the old detection: a game would
|
||||
differently.
|
||||
|
||||
A behavior with *Run in editor* sees collisions but no simulation: dynamic bodies stay where they
|
||||
are placed, because what the editor run moves is saved.
|
||||
are placed, because what the editor run moves is saved. The nodes above do nothing there.
|
||||
|
||||
## What is not there yet
|
||||
|
||||
- Forces, impulses and velocities from a graph (`Apply force`, `Apply impulse`, `Set velocity`, …)
|
||||
and `Move` over the engine's character controller – slopes, steps, pushing boxes (#147).
|
||||
- `Move` walking up slopes and over steps (#150). Rapier's character controller was measured
|
||||
for it in #147 and not taken: it caught on the seams between boxes lying side by side (10 of 100
|
||||
steps along a floor of 12 crates) and kept a gap of up to 1.7 units, where `Move` catches on
|
||||
nothing and stops flush.
|
||||
- The simulation in the editor run (#148), and `On collision stay` with contact data (#149).
|
||||
- Capsules and polygons, collision layers, raycasts, joints, one-way platforms (#144).
|
||||
Reference in new issue
Block a user