Physik: Node „Set layer“ (Kollisionsebene zur Laufzeit wechseln) #211

Closed
opened 2026-09-23 07:05:35 +02:00 by meleki · 2 comments
Owner

Aus #152 („Ein Set layer-Node ist wie besprochen nicht dabei, der kommt später.“).

Befund

  • Ein Collider trägt seit #152 eine Ebene (Layer) und eine Maske (Collides with). Die Regel liegt in src/core/model/collisionLayers.ts (layerBit, layersMeet), gelesen von CollisionSystem, solids.ts und PhysicsSystem (dort als Interaktionsgruppen von Rapier).
  • Aus einem Behavior lassen sich beide Werte nicht ändern. Es gibt keinen Node dafür und keinen allgemeinen „Set property“-Node, der sie schreiben könnte.
  • Typische Fälle: Eine Figur wird nach einem Treffer kurz unverwundbar (Ebene wechseln), ein Geist geht durch Wände, eine aufgehobene Kiste soll die Spielfigur nicht mehr blocken.

Zu bauen (Vorschlag)

  • Action-Node Set layer mit Flow, Eingang collider (Vorgabe: der eigene) und der Ebene als Einstellung wie bei Raycast (Auswahl der Projekt-Ebenen).
  • Action-Node Set collides with mit der Maske als Häkchen-Einstellung, dieselbe Feldart wie am Collider.
  • Beide wirken ab dem nächsten Schritt in Editor-Run und Play. Bei Rapier heißt das: die Interaktionsgruppen des Colliders neu setzen, nicht den Collider neu bauen.
  • Data-Node Layer of (Name der Ebene), damit man verzweigen kann.
  • Tests gegen beide Systeme: Mover wird geblockt, nach Set layer geht er durch, nach dem Zurücksetzen wieder geblockt. Raycast mit Ebenen-Filter sieht den Wechsel.

Offen (mit Vorschlag)

  1. Ebene als Einstellung oder als Eingang (Name als Text)? Vorschlag: Einstellung, dann stimmt sie immer mit den Projekt-Ebenen überein. Ein Text-Eingang wäre bei umbenannten Ebenen still falsch.
  2. Gilt die Änderung nur im Lauf? Vorschlag: ja, wie jede Laufzeitänderung in Play. Im Editor-Run schreibt sie wie alles dort ins Modell (#12).
Aus #152 („Ein `Set layer`-Node ist wie besprochen **nicht** dabei, der kommt später.“). ## Befund - Ein Collider trägt seit #152 eine Ebene (`Layer`) und eine Maske (`Collides with`). Die Regel liegt in `src/core/model/collisionLayers.ts` (`layerBit`, `layersMeet`), gelesen von `CollisionSystem`, `solids.ts` und `PhysicsSystem` (dort als Interaktionsgruppen von Rapier). - Aus einem Behavior lassen sich beide Werte nicht ändern. Es gibt keinen Node dafür und keinen allgemeinen „Set property“-Node, der sie schreiben könnte. - Typische Fälle: Eine Figur wird nach einem Treffer kurz unverwundbar (Ebene wechseln), ein Geist geht durch Wände, eine aufgehobene Kiste soll die Spielfigur nicht mehr blocken. ## Zu bauen (Vorschlag) - Action-Node **Set layer** mit Flow, Eingang `collider` (Vorgabe: der eigene) und der Ebene als Einstellung wie bei Raycast (Auswahl der Projekt-Ebenen). - Action-Node **Set collides with** mit der Maske als Häkchen-Einstellung, dieselbe Feldart wie am Collider. - Beide wirken ab dem nächsten Schritt in Editor-Run und Play. Bei Rapier heißt das: die Interaktionsgruppen des Colliders neu setzen, nicht den Collider neu bauen. - Data-Node **Layer of** (Name der Ebene), damit man verzweigen kann. - Tests gegen beide Systeme: Mover wird geblockt, nach `Set layer` geht er durch, nach dem Zurücksetzen wieder geblockt. Raycast mit Ebenen-Filter sieht den Wechsel. ## Offen (mit Vorschlag) 1. **Ebene als Einstellung oder als Eingang (Name als Text)?** Vorschlag: Einstellung, dann stimmt sie immer mit den Projekt-Ebenen überein. Ein Text-Eingang wäre bei umbenannten Ebenen still falsch. 2. **Gilt die Änderung nur im Lauf?** Vorschlag: ja, wie jede Laufzeitänderung in Play. Im Editor-Run schreibt sie wie alles dort ins Modell (#12).
meleki added the new label 2026-09-23 07:05:35 +02:00
admin added low-priorityquestion and removed new labels 2026-09-23 07:07:00 +02:00
admin added this to the Development project 2026-09-23 07:14:43 +02:00

Vorschläge passen

Vorschläge passen
admin removed the question label 2026-09-29 06:32:31 +02:00
admin moved this to Next in Development on 2026-09-29 06:32:34 +02:00
admin moved this to Done in Development on 2026-10-01 16:16:05 +02:00
Author
Owner

Done in 3e8c88c, wiki 412b94a (Colliders, Behaviors, Development). Of the three nodes proposed here only Layer of is built, as agreed after the finding below.

The finding in this issue was outdated

  • The Properties node of type Collider already writes layer and collidesWith while the game runs: add the port under + Property and switch it to Set.
  • Both systems see the change at once (editor run and Play). Measured with a throwaway probe: the mover stops at the wall at x = -14 before the change and walks through to x = 100 after it.
  • A pair that still meets after the change reports no new enter or exit, although Rapier rebuilds the collider. "Set the groups instead of rebuilding" from the proposal would only be an optimisation and is not done.
  • Set layer and Set collides with would only have saved a Child by name and been a second way to do the same thing, so they are not built. Properties takes the collider itself, not the object.

What is new

  • Layer of (data node): input object, outputs name (as the project calls the layer) and number. Feed name into Equals to branch.

Decided here

  • The node takes an object, not only a collider. An object stands for its first collider child, a collider or tilemap for itself.
  • A collider that is switched off counts too, its layer is set either way. Counting only switched-on ones (as Is touching does) would be one line.
  • Without a collider name is empty and number is -1.
  • The node answers at the moment it is asked. Right after a Set in the same flow it already names the new layer.
  • The output number was not asked for. It fits the layer port of Properties as it is.

The two open points

  1. Layer as a setting or as a text input: no longer applies, writing goes through the port of Properties, which shows the project's layers.
  2. The change lasts for the run in Play, and the editor run writes it into the scene, as proposed. That follows from how Properties writes and was not looked at in the browser.

Under the hood

  • src/core/graph/nodes/data/LayerOf.ts is a read, so nothing is cached within a pulse.
  • NodeContext.collisionLayerOf answers the number, layerHolderOf in solids.ts says whose layer counts, and the new field collisionLayers on GraphLookup brings the names to the node.

Tests (on melektaus-atx)

gate      198 files, 2929 tests, CHECK EXIT 0 (2914 + 15)
e2e 1-6   ALL PASSED - 285 checks (06: +2 for block 6z-x)
  • Five unit tests for the change during a run, which had no test at all so far:
    • a graph switches the layer on a key: the mover is blocked, passes, and is blocked again after switching back (each system)
    • a ray with a layer filter finds the collider only on the new layer (each system)
    • a dynamic body falls through the ground after the change (Play only)
  • Six unit tests for Layer of in tests/core/collision-layers.test.ts, three against each system, and four cases in the node catalog.
  • 6z-x types "layer of" into the palette and checks the ports. In a Play run a behavior logs Ghost and 1 for its owner's collider.
  • Screenshot looked at: the node sits in the graph with object, name and number, in the scaled-down "Fit" view only.
Counter-check Result
Layers taken out of the rebuild key of the physics 1 test fails (the dynamic body)
Stale filter in solids.ts 4 tests fail
Six for Layer of in the unit tests all work, 2 to 3 tests fail each
Browser: the node bent, build went through 6z-x fails with ["Layer 1","1"]
  • The unit counter-checks ran on stein2, not in the container. In the first two only new tests fail, so those places were unguarded before.
  • The e2e sum of 1619 is calculated (1617 measured in CI run 276, plus 2). Neither the full suite nor the smokes ran for this state on melektaus-atx; CI run 277 for 3e8c88c was not waited for.
  • Not looked at in the browser: that the layer port of Properties shows the same picker as the inspector. The wiki section says so from the code.
Done in `3e8c88c`, wiki `412b94a` (*Colliders*, *Behaviors*, *Development*). Of the three nodes proposed here only **Layer of** is built, as agreed after the finding below. **The finding in this issue was outdated** - The **Properties** node of type *Collider* already writes `layer` and `collidesWith` while the game runs: add the port under `+ Property` and switch it to *Set*. - Both systems see the change at once (editor run and Play). Measured with a throwaway probe: the mover stops at the wall at x = -14 before the change and walks through to x = 100 after it. - A pair that still meets after the change reports no new *enter* or *exit*, although Rapier rebuilds the collider. "Set the groups instead of rebuilding" from the proposal would only be an optimisation and is not done. - `Set layer` and `Set collides with` would only have saved a `Child by name` and been a second way to do the same thing, so they are not built. Properties takes the collider itself, not the object. **What is new** - **`Layer of`** (data node): input `object`, outputs `name` (as the project calls the layer) and `number`. Feed `name` into `Equals` to branch. **Decided here** - The node takes an object, not only a collider. An object stands for its first collider child, a collider or tilemap for itself. - A collider that is switched off counts too, its layer is set either way. Counting only switched-on ones (as `Is touching` does) would be one line. - Without a collider `name` is empty and `number` is -1. - The node answers at the moment it is asked. Right after a *Set* in the same flow it already names the new layer. - The output `number` was not asked for. It fits the `layer` port of Properties as it is. **The two open points** 1. Layer as a setting or as a text input: no longer applies, writing goes through the port of Properties, which shows the project's layers. 2. The change lasts for the run in Play, and the editor run writes it into the scene, as proposed. That follows from how Properties writes and was not looked at in the browser. **Under the hood** - `src/core/graph/nodes/data/LayerOf.ts` is a `read`, so nothing is cached within a pulse. - `NodeContext.collisionLayerOf` answers the number, `layerHolderOf` in `solids.ts` says whose layer counts, and the new field `collisionLayers` on `GraphLookup` brings the names to the node. **Tests** (on `melektaus-atx`) ``` gate 198 files, 2929 tests, CHECK EXIT 0 (2914 + 15) e2e 1-6 ALL PASSED - 285 checks (06: +2 for block 6z-x) ``` - Five unit tests for the change during a run, which had no test at all so far: - a graph switches the layer on a key: the mover is blocked, passes, and is blocked again after switching back (each system) - a ray with a layer filter finds the collider only on the new layer (each system) - a dynamic body falls through the ground after the change (Play only) - Six unit tests for `Layer of` in `tests/core/collision-layers.test.ts`, three against each system, and four cases in the node catalog. - **6z-x** types "layer of" into the palette and checks the ports. In a Play run a behavior logs `Ghost` and `1` for its owner's collider. - Screenshot looked at: the node sits in the graph with `object`, `name` and `number`, in the scaled-down "Fit" view only. | Counter-check | Result | |---|---| | Layers taken out of the rebuild key of the physics | 1 test fails (the dynamic body) | | Stale filter in `solids.ts` | 4 tests fail | | Six for `Layer of` in the unit tests | all work, 2 to 3 tests fail each | | Browser: the node bent, build went through | 6z-x fails with `["Layer 1","1"]` | - The unit counter-checks ran on stein2, not in the container. In the first two only new tests fail, so those places were unguarded before. - The e2e sum of 1619 is calculated (1617 measured in CI run 276, plus 2). Neither the full suite nor the smokes ran for this state on `melektaus-atx`; CI run 277 for `3e8c88c` was not waited for. - Not looked at in the browser: that the `layer` port of Properties shows the same picker as the inspector. The wiki section says so from the code.
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#211