Physik: Raycast mit Kollisionsebenen filtern (nach #152) #158

Closed
opened 2026-09-19 11:37:24 +02:00 by meleki · 2 comments
Owner

Aus #153 (offener Punkt 3; angefordert im Kommentar in #153). Hängt an #152.

Befund

  • Raycast (#153) trifft heute jeden blockierenden Collider und die Tilemap, Trigger nur per Schalter. Filtern kann man nur hinterher im Graph über object.
  • #152 plant benannte Ebenen (max. 16) mit Layer und Collides with am Collider und eine gemeinsame Funktion layersMeet(a, b).

Zu bauen (sobald #152 steht)

  • Raycast und Raycast all (#157) bekommen einen Eingang Layers (Mehrfachauswahl der Projekt-Ebenen): Getroffen wird nur, was auf einer der gewählten Ebenen liegt.
  • Die Prüfung läuft in Solids.raycast vor dem Schnitttest, damit Editor-Run und Play gleich antworten.
  • Tests: Strahl geht durch eine ausgeschlossene Ebene zum nächsten Collider; Tilemap auf eigener Ebene; beide Systeme.

Offen (mit Vorschlag)

  1. Vorgabe: Vorschlag „alle Ebenen“, damit bestehende Graphen gleich antworten.
  2. Ebenen des Besitzers berücksichtigen (Strahl trifft nur, womit der Besitzer kollidieren würde)? Vorschlag: nein, der Strahl hat seine eigene Auswahl; wer das will, verdrahtet es.
Aus #153 (offener Punkt 3; angefordert im Kommentar in #153). Hängt an #152. ## Befund - **Raycast** (#153) trifft heute jeden blockierenden Collider und die Tilemap, Trigger nur per Schalter. Filtern kann man nur hinterher im Graph über `object`. - #152 plant benannte Ebenen (max. 16) mit **Layer** und **Collides with** am Collider und eine gemeinsame Funktion `layersMeet(a, b)`. ## Zu bauen (sobald #152 steht) - Raycast und Raycast all (#157) bekommen einen Eingang **Layers** (Mehrfachauswahl der Projekt-Ebenen): Getroffen wird nur, was auf einer der gewählten Ebenen liegt. - Die Prüfung läuft in `Solids.raycast` vor dem Schnitttest, damit Editor-Run und Play gleich antworten. - Tests: Strahl geht durch eine ausgeschlossene Ebene zum nächsten Collider; Tilemap auf eigener Ebene; beide Systeme. ## Offen (mit Vorschlag) 1. **Vorgabe:** Vorschlag „alle Ebenen“, damit bestehende Graphen gleich antworten. 2. **Ebenen des Besitzers berücksichtigen** (Strahl trifft nur, womit der Besitzer kollidieren würde)? Vorschlag: nein, der Strahl hat seine eigene Auswahl; wer das will, verdrahtet es.
meleki added the new label 2026-09-19 11:37:24 +02:00
admin added this to the Development project 2026-09-19 12:42:48 +02:00
admin removed the new label 2026-09-19 12:42:56 +02:00

vorschläge passen

vorschläge passen
admin moved this to Next in Development on 2026-09-19 12:50:09 +02:00
meleki referenced this issue from a commit 2026-09-20 18:15:41 +02:00
The Raycast node filters by collision layers: the node gained a "Layers" setting, a tickbox per collision layer of the project - the same field kind the collider uses for "Collides with" - and the ray only hits what sits on a ticked layer, tilemaps counting as colliders; the default is every layer, and a graph without the param answers exactly as before, which is its own unit test; the check is one-sided on purpose, unlike the symmetric rule of #152: a ray is not a collider, so it never reads the collidesWith of the thing it hits - a collider that meets nothing is still seen by a ray - because who a ray may look at is the ray's business, and a unit test holds that case; the filter sits in Solids.raycast in front of the intersection test, which is the one path the editor run and Play both take, so every unit test runs through describe.each against both systems; NodeView did not know the field kinds layer/layers, so the node would have read "Layers: 65533" - it now shows the name of the layer, or "All layers"; 5 new e2e checks in the new block 43d (a shield on its own layer between the caster and the floor stops the ray, the "Layers" row on the node, the tickbox menu with the project's layers, the ray reaching 280 instead of 145 units once the shield's layer is unticked, and the mask read as a name) and 6 new unit tests, three against each system; two counter-checks hold: disarming the filter line drops 6 unit tests and the unticking check in module 43, and switching the formatting off makes the node check fail with the raw bits; two findings from measuring came out of it and stand in the wiki and the notes - __gm.rays() only measures while the Scene tab is in front, so a node selection blinds it and the block measures through a Log node on distance instead, and a running behavior instance keeps the graph it started with, so the editor run casts with the old mask until the instance is built anew (#158)
Author
Owner

Gebaut und gepusht: 0fdde6c, Wiki bc2a138.

Was gebaut wurde

Der Raycast-Node hat eine Einstellung „Layers" — ein Häkchen pro Kollisionsebene des Projekts, dieselbe Feldart, die der Collider für „Collides with" nutzt. Getroffen wird nur, was auf einer angehakten Ebene sitzt; Tilemaps zählen dabei wie Collider. Vorgabe ist jede Ebene, und ein Graph ohne den Param antwortet genau wie vorher.

Die Prüfung ist einseitig — anders als die symmetrische Regel aus #152. Der Strahl liest das collidesWith des Getroffenen nicht. Ein Strahl ist kein Collider; wen er ansehen darf, ist seine Sache. Ein Collider, der mit nichts kollidiert, wird von einem Strahl trotzdem getroffen. Das liegt als eigener Unit-Test vor und steht im Wiki.

Der Filter sitzt in Solids.raycast vor dem Schnitttest — dem einen Weg, den Editor-Run und Play beide gehen. Deshalb läuft jeder Unit-Test über describe.each gegen beide Systeme.

Nebenbei nötig: NodeView kannte die Feldarten layer/layers nicht, am Node hätte „Layers: 65533" gestanden. Jetzt steht dort der Name der Ebene bzw. „All layers".

Tests

./check.sh                       → 121 Files, 1770 Tests, CHECK EXIT 0   (vorher 1764)
npm run build                    → BUILD EXIT 0
GM_STEPS=43 (frisch geseedet)    → ALL PASSED – 13 checks   (vorher 8)
  • 5 neue e2e-Checks im neuen Block 43d: ein Schild auf eigener Ebene zwischen Caster und Boden hält den Strahl; die Zeile „Layers" am Node mit „All layers"; das Häkchen-Menü mit den Ebenen des Projekts; nach dem Abwählen geht der Strahl durch das Schild bis zum Boden (145 → 280 Einheiten, aus dem Log gemessen); und die Maske als Name statt als Bits.
  • 6 neue Unit-Tests, je 3 gegen beide Systeme: der Strahl geht durch eine ausgeschlossene Ebene zum nächsten Collider — auch dann, wenn dieser selbst mit nichts kollidiert; eine Tilemap auf eigener Ebene wird genauso getroffen oder passiert; und der Node-Param in vier Stufen.
  • Zwei Gegenproben, beide greifen: Filterzeile in Solids.raycast entschärft → 6 Unit-Tests fallen und Modul 43 fällt mit dem Abwähl-Check (reached: 145 statt 280). Formatierung am Node abgeschaltet → der Node-Check fällt mit "Layers: 65533". Originale per cmp zurückgeprüft.
  • Check-Summe 1153 (1148 + 5, gerechnet; die 1148 ist von CI an ae3aa7d bestätigt).

Zwei Funde beim Messen

  • __gm.rays() misst nur, solange der Scene-Tab vorn ist. Der Hook liefert, was der Viewport zuletzt gezeichnet hat — eine Node-Auswahl schaltet aber auf den Graph-Tab. Mein erster Testaufbau war dadurch blind und wäre auch gegen kaputten Code grün geblieben. Der Block misst jetzt über einen Log-Node an distance.
  • Eine laufende Behavior-Instanz behält den Graph, mit dem sie gestartet ist. Die Einstellung steht sofort im Projekt, der laufende Editor-Run castet aber weiter mit der alten Maske, bis die Instanz neu entsteht. Bestehendes Verhalten, kein Teil dieser Änderung — steht jetzt im Wiki, der Test schaltet „Run in editor" dafür aus und wieder an.

Doku

Wiki: Colliders (die Einstellung, die Einseitigkeit, der Hinweis zur laufenden Instanz; „ein Filter nach Ebenen kommt später" gestrichen), Physics (offene Punkte nachgezogen: bleibt #157), Behaviors (der Node), Development (Check-Summe). Nebenbei die En-Dashes aus Colliders und Physics geräumt, die Gitea als mehrdeutige Zeichen anflaggt.

Deine beiden offenen Punkte („vorschläge passen") sind so gebaut: Vorgabe „alle Ebenen", und der Strahl hat seine eigene Auswahl statt der des Besitzers.

Gebaut und gepusht: `0fdde6c`, Wiki `bc2a138`. ## Was gebaut wurde Der **Raycast-Node hat eine Einstellung „Layers"** — ein Häkchen pro Kollisionsebene des Projekts, dieselbe Feldart, die der Collider für „Collides with" nutzt. Getroffen wird nur, was auf einer angehakten Ebene sitzt; Tilemaps zählen dabei wie Collider. Vorgabe ist jede Ebene, und ein Graph ohne den Param antwortet genau wie vorher. **Die Prüfung ist einseitig — anders als die symmetrische Regel aus #152.** Der Strahl liest das `collidesWith` des Getroffenen nicht. Ein Strahl ist kein Collider; wen er ansehen darf, ist seine Sache. Ein Collider, der mit nichts kollidiert, wird von einem Strahl trotzdem getroffen. Das liegt als eigener Unit-Test vor und steht im Wiki. Der Filter sitzt in **`Solids.raycast` vor dem Schnitttest** — dem einen Weg, den Editor-Run und Play beide gehen. Deshalb läuft jeder Unit-Test über `describe.each` gegen beide Systeme. Nebenbei nötig: `NodeView` kannte die Feldarten `layer`/`layers` nicht, am Node hätte „Layers: 65533" gestanden. Jetzt steht dort der Name der Ebene bzw. „All layers". ## Tests ``` ./check.sh → 121 Files, 1770 Tests, CHECK EXIT 0 (vorher 1764) npm run build → BUILD EXIT 0 GM_STEPS=43 (frisch geseedet) → ALL PASSED – 13 checks (vorher 8) ``` - **5 neue e2e-Checks** im neuen Block 43d: ein Schild auf eigener Ebene zwischen Caster und Boden hält den Strahl; die Zeile „Layers" am Node mit „All layers"; das Häkchen-Menü mit den Ebenen des Projekts; nach dem Abwählen geht der Strahl durch das Schild bis zum Boden (145 → 280 Einheiten, aus dem Log gemessen); und die Maske als Name statt als Bits. - **6 neue Unit-Tests**, je 3 gegen beide Systeme: der Strahl geht durch eine ausgeschlossene Ebene zum nächsten Collider — auch dann, wenn dieser selbst mit nichts kollidiert; eine Tilemap auf eigener Ebene wird genauso getroffen oder passiert; und der Node-Param in vier Stufen. - **Zwei Gegenproben, beide greifen:** Filterzeile in `Solids.raycast` entschärft → 6 Unit-Tests fallen und Modul 43 fällt mit dem Abwähl-Check (`reached: 145` statt 280). Formatierung am Node abgeschaltet → der Node-Check fällt mit `"Layers: 65533"`. Originale per `cmp` zurückgeprüft. - Check-Summe **1153** (1148 + 5, gerechnet; die 1148 ist von CI an `ae3aa7d` bestätigt). ## Zwei Funde beim Messen - **`__gm.rays()` misst nur, solange der Scene-Tab vorn ist.** Der Hook liefert, was der Viewport zuletzt gezeichnet hat — eine Node-Auswahl schaltet aber auf den Graph-Tab. Mein erster Testaufbau war dadurch blind und wäre auch gegen kaputten Code grün geblieben. Der Block misst jetzt über einen `Log`-Node an `distance`. - **Eine laufende Behavior-Instanz behält den Graph, mit dem sie gestartet ist.** Die Einstellung steht sofort im Projekt, der laufende Editor-Run castet aber weiter mit der alten Maske, bis die Instanz neu entsteht. Bestehendes Verhalten, kein Teil dieser Änderung — steht jetzt im Wiki, der Test schaltet „Run in editor" dafür aus und wieder an. ## Doku Wiki: Colliders (die Einstellung, die Einseitigkeit, der Hinweis zur laufenden Instanz; „ein Filter nach Ebenen kommt später" gestrichen), Physics (offene Punkte nachgezogen: bleibt #157), Behaviors (der Node), Development (Check-Summe). Nebenbei die En-Dashes aus Colliders und Physics geräumt, die Gitea als mehrdeutige Zeichen anflaggt. Deine beiden offenen Punkte („vorschläge passen") sind so gebaut: Vorgabe „alle Ebenen", und der Strahl hat seine eigene Auswahl statt der des Besitzers.
admin moved this to Done in Development on 2026-09-20 18:28:17 +02:00
meleki referenced this issue from a commit 2026-09-20 18:54:21 +02:00
The new node "Raycast all" answers with every collider along the ray instead of only the nearest one: it carries the same inputs and settings as Raycast (Ignore owner, Hit triggers, Layers from #158) plus "max hits" where 0 means all, and it hands back parallel lists sorted by distance - objects, colliders, points x/y, normals x/y, distances - next to count, so index i of every list speaks about the same hit; a collider counts once no matter how many convex parts its shape is built from, while a tilemap counts per cell it is hit in, and the filter sits in Solids.raycastAll like the one of #158, the one path the editor run and Play both take, so all 12 new unit tests run through describe.each against both systems; the node needed the value system to learn something it could not do - a graph list carried numbers, text, booleans and bundles but no object handles, asList turned an object into its name, so objects/colliders would have been lists of names, which loses the object when two carry the same name, and collider children usually do; Value now knows a travelling list that may hold handles and "Item at" gives such an item out as an object, ready for Destroy, Apply force or Name of, while the single door into a stored file - writeTyped/asTypeOf - runs the list through the new storedList() so every object becomes its name again and nothing living reaches a project file, which is its own unit test over JSON.stringify; three list nodes follow the handles: "Index of" compares objects by identity because a name is not the object of that name, "Set item" and "Fill" write an object as an object, and "Join text" prints the names instead of the innards; this decision was mine to make because the question ran into the MCP timeout - the alternative was a list of names plus "Object by name", which is the smaller change but lossy; 4 new e2e checks in the new block 43e (shield and floor in one go reading 2 and "145, 280", the second object answering to its name, which only a real object in a list can do, "max hits" 1 stopping at the nearest, and the node showing the row) and 18 new unit tests, 12 in raycast.test.ts, 4 on the value system and 2 in the node catalog; two counter-checks hold: not counting tilemap cells one by one drops 2 unit tests, and answering with the nearest hit only drops module 43 with 2 FAILs; one finding on the way - the node read "maxHits" while every other input carries a spoken label, because int() took the key as its label, so it has a third parameter now, and the e2e check caught that, no unit test did (#157)
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#158