Aus #153 (offener Punkt 2, dort auf „später“ gesetzt; angefordert im Kommentar in #153).
Befund
Der Node Raycast (#153) liefert nur den ersten Treffer. Für Durchschuss, Laser durch mehrere Gegner oder „was liegt alles auf der Linie“ braucht es alle Treffer.
Die Geometrie ist schon da: rayCast in src/core/properties/ray.ts rechnet pro Form in f64, Solids.raycast geht über dieselben Colliderlisten in Editor-Run und Play und nimmt heute nur den nächsten.
Der Graph kennt den Port-Typ list samt Nodes Count, Item at, Sub list, Index of. Einen Datensatz-Typ (ein Treffer mit mehreren Feldern) gibt es nicht.
Zu bauen
Eigener Node Raycast all (Action mit Flow), gleiche Eingänge wie Raycast (Start, Richtung, Länge, „Ignore owner“, „Hit triggers“).
Ausgänge als parallele Listen, nach Distanz sortiert: objects, colliders, points x, points y, normals x, normals y, distances, dazu count.
Pro Collider zählt ein Treffer (der erste Eintritt), eine Tilemap liefert pro getroffener Zelle einen. One-Way-Collider nur von ihrer blockierenden Seite, wie bei Raycast.
Tests gegen beide Systeme: Reihenfolge nach Distanz, Collider aus mehreren Polygon-Teilen zählt einmal, Tilemap-Zellen, Start innen.
Offen (mit Vorschlag)
Parallele Listen oder ein Treffer pro Flow-Durchlauf (For-each-artig)? Vorschlag: parallele Listen, das passt zu den vorhandenen Listen-Nodes und braucht keinen neuen Typ.
Obergrenze an Treffern? Vorschlag: Eingang max hits, Vorgabe 0 = alle.
Kollisionsebenen: Filter-Eingang erst mit #152, siehe #158.
Aus #153 (offener Punkt 2, dort auf „später“ gesetzt; angefordert im Kommentar in #153).
## Befund
- Der Node **Raycast** (#153) liefert nur den **ersten** Treffer. Für Durchschuss, Laser durch mehrere Gegner oder „was liegt alles auf der Linie“ braucht es alle Treffer.
- Die Geometrie ist schon da: `rayCast` in `src/core/properties/ray.ts` rechnet pro Form in f64, `Solids.raycast` geht über dieselben Colliderlisten in Editor-Run und Play und nimmt heute nur den nächsten.
- Der Graph kennt den Port-Typ `list` samt Nodes `Count`, `Item at`, `Sub list`, `Index of`. Einen Datensatz-Typ (ein Treffer mit mehreren Feldern) gibt es nicht.
## Zu bauen
- Eigener Node **Raycast all** (Action mit Flow), gleiche Eingänge wie Raycast (Start, Richtung, Länge, „Ignore owner“, „Hit triggers“).
- Ausgänge als **parallele Listen, nach Distanz sortiert**: objects, colliders, points x, points y, normals x, normals y, distances, dazu `count`.
- Pro Collider zählt ein Treffer (der erste Eintritt), eine Tilemap liefert pro getroffener Zelle einen. One-Way-Collider nur von ihrer blockierenden Seite, wie bei Raycast.
- Tests gegen beide Systeme: Reihenfolge nach Distanz, Collider aus mehreren Polygon-Teilen zählt einmal, Tilemap-Zellen, Start innen.
## Offen (mit Vorschlag)
1. **Parallele Listen oder ein Treffer pro Flow-Durchlauf (For-each-artig)?** Vorschlag: parallele Listen, das passt zu den vorhandenen Listen-Nodes und braucht keinen neuen Typ.
2. **Obergrenze an Treffern?** Vorschlag: Eingang `max hits`, Vorgabe 0 = alle.
3. **Kollisionsebenen:** Filter-Eingang erst mit #152, siehe #158.
meleki
added the new label 2026-09-19 11:37:23 +02:00
Raycast all trägt dieselben Eingänge und Einstellungen wie Raycast — Ignore owner, Hit triggers, Layers (aus #158) — dazu max hits, wobei 0 „alle" heißt. Heraus kommen nach Distanz sortierte parallele Listen: objects, colliders, points x, points y, normals x, normals y, distances, dazu count. Index i jeder Liste spricht über denselben Treffer.
Ein Collider zählt einmal, egal aus wie vielen konvexen Teilen seine Form gebaut ist.
Eine Tilemap zählt pro getroffener Zelle.
Der Filter sitzt in Solids.raycastAll — wie der von #158 im einen Weg, den Editor-Run und Play beide gehen.
Eine Entscheidung, die ich selbst getroffen habe
Die Rückfrage ist ins MCP-Timeout gelaufen (300 s), deshalb steht hier, was entschieden wurde und warum.
Eine Graph-Liste konnte Zahlen, Text, Wahrheitswerte und Bündel tragen — keine Objekt-Handles; asList machte aus einem Objekt seinen Namen. objects/colliders wären also Namenslisten geworden, und das ist verlustbehaftet: gleichnamige Objekte sind nicht zu unterscheiden, und Collider-Kinder heißen meistens gleich.
Gebaut ist deshalb: Listen dürfen Objekte tragen.
Value kennt eine reisende Liste mit Handles; Item at gibt ein solches Item als Objekt heraus — fertig für Destroy, Apply force, Name of.
Die einzige Tür in eine gespeicherte Datei ist writeTyped/asTypeOf. Dort läuft die Liste durch das neue storedList(), aus jedem Objekt wird wieder sein Name. Nichts Lebendiges landet in einer Projektdatei — eigener Unit-Test über JSON.stringify.
Handle-sicher nachgezogen: Index of vergleicht Objekte nach Identität (ein Name ist nicht das Objekt dieses Namens), Set item und Fill schreiben ein Objekt als Objekt, Join text druckt die Namen statt des Innenlebens.
Die Alternative wäre eine Namensliste plus Object by name gewesen — kleinerer Eingriff, aber verlustbehaftet.
Die volle Suite lief lokal, nicht nur in CI, weil die Änderung am Wertesystem in jedem Graphen steckt.
4 neue e2e-Checks (Block 43e): Schild und Boden in einem Zug (2, 145, 280); das zweite getroffene Objekt antwortet auf seinen Namen — was nur ein echtes Objekt in der Liste kann; max hits 1 hält beim Nächsten an; der Node zeigt die Zeile „max hits" samt derselben Layers-Einstellung.
18 neue Unit-Tests: 12 in raycast.test.ts (je 6 gegen beide Systeme: Reihenfolge und Deckung mit dem einfachen Cast, mehrteiliger Collider zählt einmal, die drei Filter, Tilemap-Zellen, max hits, der Node im Graphen), 4 zum Wertesystem, 2 im Node-Katalog.
Zwei Gegenproben, beide greifen: Tilemap-Zellen nicht einzeln zählen → 2 Unit-Tests fallen; nur den nächsten Treffer liefern → Modul 43 fällt mit 2 FAILs (count: 1, kein zweites Objekt). Originale per cmp zurückgeprüft und neu gebaut.
Screenshot angesehen (43-ray-all): Node mit Layers und „max hits", Konsole mit 2 / 145, 280 / Query ground / 145.
Drei Funde
Am Node stand „maxHits", während jeder andere Eingang eine gesprochene Beschriftung trägt: int() nahm den Schlüssel als Beschriftung und hat jetzt einen dritten Parameter. Gefangen hat das der e2e-Check, kein Unit-Test.
Modul 43 ist nicht idempotent. Zweimal hintereinander ohne frisches node tools/seed-e2e.mjs fällt Block 43a (Dropper/Jumper). Liegt nicht an dieser Änderung, steht jetzt in den Projektnotizen.
Beim ersten Blick auf den verkleinerten Screenshot habe ich „1" statt „2" gelesen. Nachgemessen (vergrößerter Ausschnitt plus Diagnose-Check im Lauf): der Node meldet durchgehend 2 Treffer, es gab nichts zu beheben.
Doku
Wiki: Colliders (neuer Abschnitt Raycast all; die Zeile „nur der erste Treffer, #157 kommt später" ist raus), Behaviors (der Node in der Liste; der Absatz zu Listen sagt jetzt, was eine reisende Liste darf und was beim Speichern passiert), Physics (offene Punkte: bleibt #154), Architecture (storedList), Development. Check-Summe 1157 in README und Wiki, gemessen.
CI zu ffdf0a8 läuft; darauf wurde auftragsgemäß nicht gewartet.
Umgesetzt in [`ffdf0a8`](http://localhost:3000/meleki/game-maker/commit/ffdf0a8), Wiki in [`77b6aa1`](http://localhost:3000/meleki/game-maker.wiki/commit/77b6aa1).
## Der Node
`Raycast all` trägt dieselben Eingänge und Einstellungen wie `Raycast` — Ignore owner, Hit triggers, Layers (aus #158) — dazu **`max hits`**, wobei 0 „alle" heißt. Heraus kommen nach Distanz sortierte **parallele Listen**: `objects`, `colliders`, `points x`, `points y`, `normals x`, `normals y`, `distances`, dazu `count`. Index *i* jeder Liste spricht über denselben Treffer.
- Ein Collider zählt **einmal**, egal aus wie vielen konvexen Teilen seine Form gebaut ist.
- Eine **Tilemap** zählt **pro getroffener Zelle**.
- Der Filter sitzt in `Solids.raycastAll` — wie der von #158 im einen Weg, den Editor-Run und Play beide gehen.
## Eine Entscheidung, die ich selbst getroffen habe
Die Rückfrage ist ins MCP-Timeout gelaufen (300 s), deshalb steht hier, was entschieden wurde und warum.
Eine Graph-Liste konnte Zahlen, Text, Wahrheitswerte und Bündel tragen — **keine Objekt-Handles**; `asList` machte aus einem Objekt seinen Namen. `objects`/`colliders` wären also Namenslisten geworden, und das ist verlustbehaftet: gleichnamige Objekte sind nicht zu unterscheiden, und Collider-Kinder heißen meistens gleich.
Gebaut ist deshalb: **Listen dürfen Objekte tragen.**
- `Value` kennt eine **reisende** Liste mit Handles; `Item at` gibt ein solches Item als Objekt heraus — fertig für `Destroy`, `Apply force`, `Name of`.
- Die **einzige Tür in eine gespeicherte Datei** ist `writeTyped`/`asTypeOf`. Dort läuft die Liste durch das neue `storedList()`, aus jedem Objekt wird wieder sein Name. Nichts Lebendiges landet in einer Projektdatei — eigener Unit-Test über `JSON.stringify`.
- Handle-sicher nachgezogen: `Index of` vergleicht Objekte nach **Identität** (ein Name ist nicht das Objekt dieses Namens), `Set item` und `Fill` schreiben ein Objekt als Objekt, `Join text` druckt die Namen statt des Innenlebens.
Die Alternative wäre eine Namensliste plus `Object by name` gewesen — kleinerer Eingriff, aber verlustbehaftet.
## Tests
```
./check.sh → 121 Files, 1788 Tests, CHECK EXIT 0 (vorher 1770)
npm run build → BUILD EXIT 0
node tools/e2e.mjs (alle Module) → ALL PASSED – 1157 checks
GM_STEPS=43 (frisch geseedet) → ALL PASSED – 17 checks (vorher 13)
```
Die volle Suite lief **lokal**, nicht nur in CI, weil die Änderung am Wertesystem in jedem Graphen steckt.
- **4 neue e2e-Checks** (Block 43e): Schild und Boden in einem Zug (`2`, `145, 280`); das zweite getroffene Objekt antwortet auf seinen Namen — was nur ein echtes Objekt in der Liste kann; `max hits` 1 hält beim Nächsten an; der Node zeigt die Zeile „max hits" samt derselben Layers-Einstellung.
- **18 neue Unit-Tests:** 12 in `raycast.test.ts` (je 6 gegen beide Systeme: Reihenfolge und Deckung mit dem einfachen Cast, mehrteiliger Collider zählt einmal, die drei Filter, Tilemap-Zellen, `max hits`, der Node im Graphen), 4 zum Wertesystem, 2 im Node-Katalog.
- **Zwei Gegenproben, beide greifen:** Tilemap-Zellen nicht einzeln zählen → 2 Unit-Tests fallen; nur den nächsten Treffer liefern → Modul 43 fällt mit 2 FAILs (`count: 1`, kein zweites Objekt). Originale per `cmp` zurückgeprüft und neu gebaut.
- **Screenshot angesehen** (`43-ray-all`): Node mit Layers und „max hits", Konsole mit `2` / `145, 280` / `Query ground` / `145`.
## Drei Funde
- **Am Node stand „maxHits"**, während jeder andere Eingang eine gesprochene Beschriftung trägt: `int()` nahm den Schlüssel als Beschriftung und hat jetzt einen dritten Parameter. Gefangen hat das der e2e-Check, kein Unit-Test.
- **Modul 43 ist nicht idempotent.** Zweimal hintereinander ohne frisches `node tools/seed-e2e.mjs` fällt Block 43a (Dropper/Jumper). Liegt nicht an dieser Änderung, steht jetzt in den Projektnotizen.
- Beim ersten Blick auf den verkleinerten Screenshot habe ich „1" statt „2" gelesen. Nachgemessen (vergrößerter Ausschnitt plus Diagnose-Check im Lauf): der Node meldet durchgehend 2 Treffer, es gab nichts zu beheben.
## Doku
Wiki: **Colliders** (neuer Abschnitt *Raycast all*; die Zeile „nur der erste Treffer, #157 kommt später" ist raus), **Behaviors** (der Node in der Liste; der Absatz zu Listen sagt jetzt, was eine reisende Liste darf und was beim Speichern passiert), **Physics** (offene Punkte: bleibt #154), **Architecture** (`storedList`), **Development**. Check-Summe **1157** in README und Wiki, **gemessen**.
CI zu `ffdf0a8` läuft; darauf wurde auftragsgemäß nicht gewartet.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Aus #153 (offener Punkt 2, dort auf „später“ gesetzt; angefordert im Kommentar in #153).
Befund
rayCastinsrc/core/properties/ray.tsrechnet pro Form in f64,Solids.raycastgeht über dieselben Colliderlisten in Editor-Run und Play und nimmt heute nur den nächsten.listsamt NodesCount,Item at,Sub list,Index of. Einen Datensatz-Typ (ein Treffer mit mehreren Feldern) gibt es nicht.Zu bauen
count.Offen (mit Vorschlag)
max hits, Vorgabe 0 = alle.vorschläge passen, zu 3. auch klar, zuerst muss es kollisionsebenen überhaupt mal geben bevor wir das umsetzen können
Umgesetzt in
ffdf0a8, Wiki in77b6aa1.Der Node
Raycast allträgt dieselben Eingänge und Einstellungen wieRaycast— Ignore owner, Hit triggers, Layers (aus #158) — dazumax hits, wobei 0 „alle" heißt. Heraus kommen nach Distanz sortierte parallele Listen:objects,colliders,points x,points y,normals x,normals y,distances, dazucount. Index i jeder Liste spricht über denselben Treffer.Solids.raycastAll— wie der von #158 im einen Weg, den Editor-Run und Play beide gehen.Eine Entscheidung, die ich selbst getroffen habe
Die Rückfrage ist ins MCP-Timeout gelaufen (300 s), deshalb steht hier, was entschieden wurde und warum.
Eine Graph-Liste konnte Zahlen, Text, Wahrheitswerte und Bündel tragen — keine Objekt-Handles;
asListmachte aus einem Objekt seinen Namen.objects/colliderswären also Namenslisten geworden, und das ist verlustbehaftet: gleichnamige Objekte sind nicht zu unterscheiden, und Collider-Kinder heißen meistens gleich.Gebaut ist deshalb: Listen dürfen Objekte tragen.
Valuekennt eine reisende Liste mit Handles;Item atgibt ein solches Item als Objekt heraus — fertig fürDestroy,Apply force,Name of.writeTyped/asTypeOf. Dort läuft die Liste durch das neuestoredList(), aus jedem Objekt wird wieder sein Name. Nichts Lebendiges landet in einer Projektdatei — eigener Unit-Test überJSON.stringify.Index ofvergleicht Objekte nach Identität (ein Name ist nicht das Objekt dieses Namens),Set itemundFillschreiben ein Objekt als Objekt,Join textdruckt die Namen statt des Innenlebens.Die Alternative wäre eine Namensliste plus
Object by namegewesen — kleinerer Eingriff, aber verlustbehaftet.Tests
Die volle Suite lief lokal, nicht nur in CI, weil die Änderung am Wertesystem in jedem Graphen steckt.
2,145, 280); das zweite getroffene Objekt antwortet auf seinen Namen — was nur ein echtes Objekt in der Liste kann;max hits1 hält beim Nächsten an; der Node zeigt die Zeile „max hits" samt derselben Layers-Einstellung.raycast.test.ts(je 6 gegen beide Systeme: Reihenfolge und Deckung mit dem einfachen Cast, mehrteiliger Collider zählt einmal, die drei Filter, Tilemap-Zellen,max hits, der Node im Graphen), 4 zum Wertesystem, 2 im Node-Katalog.count: 1, kein zweites Objekt). Originale percmpzurückgeprüft und neu gebaut.43-ray-all): Node mit Layers und „max hits", Konsole mit2/145, 280/Query ground/145.Drei Funde
int()nahm den Schlüssel als Beschriftung und hat jetzt einen dritten Parameter. Gefangen hat das der e2e-Check, kein Unit-Test.node tools/seed-e2e.mjsfällt Block 43a (Dropper/Jumper). Liegt nicht an dieser Änderung, steht jetzt in den Projektnotizen.Doku
Wiki: Colliders (neuer Abschnitt Raycast all; die Zeile „nur der erste Treffer, #157 kommt später" ist raus), Behaviors (der Node in der Liste; der Absatz zu Listen sagt jetzt, was eine reisende Liste darf und was beim Speichern passiert), Physics (offene Punkte: bleibt #154), Architecture (
storedList), Development. Check-Summe 1157 in README und Wiki, gemessen.CI zu
ffdf0a8läuft; darauf wurde auftragsgemäß nicht gewartet.