Physik Stufe 1b: Force-, Impulse- und Velocity-Nodes, Move über den Character-Controller #147

Closed
opened 2026-09-18 17:48:09 +02:00 by meleki · 1 comment
Owner

Zweiter Teil von #146 (Aufteilung laut Antwort 1 dort). Voraussetzung: #146 (Rigidbody, Material, Schwerkraft, PhysicsSystem).

Stand nach #146

  • Dynamic Bodies fallen, prallen ab und liegen. Aus dem Graph lassen sie sich aber nur versetzen: Move ohne Kollision setzt die Position, der Body behält dabei seine Geschwindigkeit.
  • PhysicsSystem hat schon velocityOf(owner) und setVelocity(owner, v), beides in Welteinheiten pro Sekunde. Bisher nutzen das nur die Unit-Tests.
  • Move mit „Collide with solids“ läuft weiter über das eigene Move-and-Slide (runtime/systems/solids.ts). Ein Dynamic Body blockiert es wie eine Wand, schieben lässt er sich damit also nicht.

Zu bauen

  • Nodes: Apply force, Apply impulse, Set velocity, Get velocity, Set angular velocity, Set gravity (Scene). Alle Größen in Welteinheiten, die Umrechnung macht engine.ts.
  • Move mit „Collide with solids“ läuft über Rapiers KinematicCharacterController: Gleiten an Wänden, Schrägen, Stufen, und Dynamic Bodies, die dabei im Weg stehen, bekommen einen Stoß. Ohne Rigidbody und bei Kinematic wie bisher (#146, Antwort 3 in #144).
  • Move auf einem Dynamic Body (Antwort 3 in #146): Das Objekt wird versetzt, die Geschwindigkeit bleibt. Beim ersten Mal steht ein Hinweis in der Console, dass Force, Impulse und Velocity der Weg sind.

Offen

  • Welche Unterschiede zu Move-and-Slide der Character-Controller im Nachkommabereich macht (Smokes, e2e 08/40). Jede umgestellte Zahl kommt in den Abschlusskommentar.
Zweiter Teil von #146 (Aufteilung laut Antwort 1 dort). Voraussetzung: #146 (Rigidbody, Material, Schwerkraft, `PhysicsSystem`). ## Stand nach #146 - Dynamic Bodies fallen, prallen ab und liegen. Aus dem Graph lassen sie sich aber nur versetzen: `Move` ohne Kollision setzt die Position, der Body behält dabei seine Geschwindigkeit. - `PhysicsSystem` hat schon `velocityOf(owner)` und `setVelocity(owner, v)`, beides in Welteinheiten pro Sekunde. Bisher nutzen das nur die Unit-Tests. - `Move` mit „Collide with solids“ läuft weiter über das eigene Move-and-Slide (`runtime/systems/solids.ts`). Ein Dynamic Body blockiert es wie eine Wand, schieben lässt er sich damit also nicht. ## Zu bauen - **Nodes:** `Apply force`, `Apply impulse`, `Set velocity`, `Get velocity`, `Set angular velocity`, `Set gravity` (Scene). Alle Größen in Welteinheiten, die Umrechnung macht `engine.ts`. - **`Move` mit „Collide with solids“** läuft über Rapiers `KinematicCharacterController`: Gleiten an Wänden, Schrägen, Stufen, und Dynamic Bodies, die dabei im Weg stehen, bekommen einen Stoß. Ohne Rigidbody und bei Kinematic wie bisher (#146, Antwort 3 in #144). - **`Move` auf einem Dynamic Body** (Antwort 3 in #146): Das Objekt wird versetzt, die Geschwindigkeit bleibt. Beim ersten Mal steht ein Hinweis in der Console, dass Force, Impulse und Velocity der Weg sind. ## Offen - Welche Unterschiede zu Move-and-Slide der Character-Controller im Nachkommabereich macht (Smokes, e2e 08/40). Jede umgestellte Zahl kommt in den Abschlusskommentar.
admin added this to the Development project 2026-09-18 18:01:02 +02:00
admin moved this to Next in Development on 2026-09-18 18:01:18 +02:00
Author
Owner

Umgesetzt – Repo 0ff3c8b + 328f978 + d931e66, Wiki d6190ec

Abweichung vom Issue: Move läuft nicht über Rapiers Character-Controller

Gemessen mit Wegwerf-Sonden gegen Rapier 0.20:

Fall Rapiers Controller eigenes Move-and-Slide
Boden aus 12 Kisten, 100 Schritte mit Schwerkraft 10× hängen, Lücke bis 1,7 px hängt nie, bündig
dasselbe mit normalNudgeFactor 5e-4 0× hängen, Lücke ~0,1 px –
Wand aus 3 gestapelten Rechtecken, 60 Schritte daran entlang 2× hängen (auch mit Tuning) hängt nie
  • Der Controller sieht nur den Stand des letzten Physik-Steps: eine danach versetzte Wand durchquert er (250 px).
  • Auffrischen per Step mit dt = 0 verändert die Simulation (Drehung einer fliegenden Kiste ging verloren, ein Kontakt-Event fehlte).

Die Rückfrage dazu lief ins Timeout, entschieden wurde nach Empfehlung: eigenes Move-and-Slide behalten, Schieben selbst dazubauen.

Was drin ist

  • Sechs Nodes, nur im Play und nur auf Dynamic Bodies:
    • Apply force wirkt über die Dauer des Frames, gemessen unabhängig von 30/60/144 fps
    • Apply impulse, Set velocity, Set angular velocity
    • Get velocity (Data-Node, inkl. Drehgeschwindigkeit in °/s)
    • Set gravity gilt für den restlichen Lauf, die Scene im Projekt bleibt unverändert
  • Hinweis einmal pro Objekt in Log und Console: Node auf ein Objekt ohne Dynamic Body; Dynamic Body direkt versetzt (Antwort 3 in #146).
  • Move mit Kollision schiebt Dynamic Bodies: Mover bleibt bündig stehen, die Kiste bekommt einen Stoß (unelastisch, abhängig von beiden Massen).

Selbst entschieden:

  • Bei Fixed rotation setzt Set angular velocity nichts – Rapier würde den Wert sonst halten, nach dem Entsperren schnellte die Kiste gemessen 133° herum.
  • On start kommt vor dem ersten Physik-Schritt; damit ein Startschuss wirkt, wird der fehlende Body in dem Moment angelegt.

Tests

npm run check                            → 104 Files, 1454 Tests (vorher 1430), CHECK EXIT 0
GM_STEPS=1-8,39,40,41 (frisch geseedet)  → ALL PASSED – 320 checks
CI zu d931e66 (Tasks 136/137)            → CHECK EXIT 0, ALL PASSED – 1055 checks, Smokes 24/19/21
  • In CI misst 41b jetzt peaks: [99.8, 61.8, 37.9, 23.2], dieselben Werte wie lokal.
  • 24 neue Unit-Tests (15 Node-Katalog, 9 gegen die Engine). Schieben in 1 s: gleich schwere Kiste 133 Einheiten, 39× schwerere 0,2, statische 0; Kinematic-Mover mit Mass 40 schiebt die schwere Kiste 142.
  • Alle bisherigen Kollisionstests laufen unverändert ohne Toleranz gegen beide Systeme.
  • Gegenprobe mit 8 eingebauten Fehlern, alle gefangen.
  • e2e 41c (3 Checks im echten Play): Kiste gleitet mit 100,8 Einheiten/s (erwartet 100), Move schiebt eine Kiste 229,9 Einheiten weit, Console ohne [physics]-Hinweis.

Zwei Nachbesserungen nach rotem CI

  • 328f978 – echter Bug: Die Suite zu 0ff3c8b hatte 2 FAILs in 41c. Ursache: Jedes project-Event während Play ließ World.syncFromModel() die Scene-Props neu kopieren und setzte damit die Schwerkraft aus Set gravity auf die gespeicherten 980 zurück; der zweite FAIL (Walker 0,11 px in der Kiste) war nur die Folge – die geschobene Kiste fiel und flog in X neben dem Walker her. Fix: World.setSceneProp() merkt sich, was der Lauf selbst an der Scene gesetzt hat, und syncFromModel legt es wieder darüber. Unit-Test liest das Modell mitten im Lauf neu (ohne Fix rot), 41c erzwingt direkt nach Play ein project-Event (gegen den alten Build lokal beide Checks rot, wie in CI).
  • d931e66 – flatternder Test: Die Suite zu 328f978 war rot in 41b (Bounce), peaks: [61.8, 37.9]. Der Check suchte Landungen über „Ball näher als 1 px am Boden“; der Ball landet mit ~9 px pro Frame, ob ein gezeichneter Frame das trifft, hängt an der Phase zwischen zwei Physik-Schritten. CI hat die erste Landung verpasst und den zweiten Abprall als ersten gelesen – die Physik selbst stimmte (Verhältnisse 0,62/0,61 bei Bounciness 0,8). Der Check sucht jetzt Umkehrpunkte. Gegenprobe am nachgebauten Sprung über 50 Phasen: alt 15/50 grün, neu 50/50; lokal 3 Läufe GM_STEPS=39,40,41 grün mit 99,8 → 61,8 → 37,9 → 23,2.

Offen / Folge

  • #150 (umgeschrieben): Move-and-Slide entlang der Kontaktnormale mit Friction, Ausgänge hit/normal, ohne Stufen und ohne Character-Controller.
  • Nebenbefund, nicht angefasst: Move mit Kollision bewegt ein Objekt ohne eigenen Collider gar nicht (schon vor #147, in beiden Systemen).

Doku: Wiki Physics (neu: Moving bodies from a graph, Schieben), Behaviors, Colliders, Architecture, Development; Check-Summe 1055.

## Umgesetzt – Repo `0ff3c8b` + `328f978` + `d931e66`, Wiki `d6190ec` ### Abweichung vom Issue: `Move` läuft **nicht** über Rapiers Character-Controller Gemessen mit Wegwerf-Sonden gegen Rapier 0.20: | Fall | Rapiers Controller | eigenes Move-and-Slide | |---|---|---| | Boden aus 12 Kisten, 100 Schritte mit Schwerkraft | 10× hängen, Lücke bis 1,7 px | hängt nie, bündig | | dasselbe mit `normalNudgeFactor` 5e-4 | 0× hängen, Lücke ~0,1 px | – | | Wand aus 3 gestapelten Rechtecken, 60 Schritte daran entlang | 2× hängen (auch mit Tuning) | hängt nie | - Der Controller sieht nur den Stand des letzten Physik-Steps: eine danach versetzte Wand durchquert er (250 px). - Auffrischen per Step mit `dt = 0` verändert die Simulation (Drehung einer fliegenden Kiste ging verloren, ein Kontakt-Event fehlte). Die Rückfrage dazu lief ins Timeout, entschieden wurde nach Empfehlung: eigenes Move-and-Slide behalten, Schieben selbst dazubauen. ### Was drin ist - **Sechs Nodes**, nur im Play und nur auf Dynamic Bodies: - **Apply force** wirkt über die Dauer des Frames, gemessen unabhängig von 30/60/144 fps - **Apply impulse**, **Set velocity**, **Set angular velocity** - **Get velocity** (Data-Node, inkl. Drehgeschwindigkeit in °/s) - **Set gravity** gilt für den restlichen Lauf, die Scene im Projekt bleibt unverändert - **Hinweis einmal pro Objekt** in Log und Console: Node auf ein Objekt ohne Dynamic Body; Dynamic Body direkt versetzt (Antwort 3 in #146). - **`Move` mit Kollision schiebt Dynamic Bodies:** Mover bleibt bündig stehen, die Kiste bekommt einen Stoß (unelastisch, abhängig von beiden Massen). **Selbst entschieden:** - Bei Fixed rotation setzt `Set angular velocity` nichts – Rapier würde den Wert sonst halten, nach dem Entsperren schnellte die Kiste gemessen 133° herum. - `On start` kommt vor dem ersten Physik-Schritt; damit ein Startschuss wirkt, wird der fehlende Body in dem Moment angelegt. ### Tests ``` npm run check → 104 Files, 1454 Tests (vorher 1430), CHECK EXIT 0 GM_STEPS=1-8,39,40,41 (frisch geseedet) → ALL PASSED – 320 checks CI zu d931e66 (Tasks 136/137) → CHECK EXIT 0, ALL PASSED – 1055 checks, Smokes 24/19/21 ``` - In CI misst 41b jetzt `peaks: [99.8, 61.8, 37.9, 23.2]`, dieselben Werte wie lokal. - 24 neue Unit-Tests (15 Node-Katalog, 9 gegen die Engine). Schieben in 1 s: gleich schwere Kiste 133 Einheiten, 39× schwerere 0,2, statische 0; Kinematic-Mover mit Mass 40 schiebt die schwere Kiste 142. - Alle bisherigen Kollisionstests laufen unverändert **ohne Toleranz** gegen beide Systeme. - Gegenprobe mit 8 eingebauten Fehlern, alle gefangen. - e2e 41c (3 Checks im echten Play): Kiste gleitet mit 100,8 Einheiten/s (erwartet 100), `Move` schiebt eine Kiste 229,9 Einheiten weit, Console ohne `[physics]`-Hinweis. ### Zwei Nachbesserungen nach rotem CI - **`328f978` – echter Bug:** Die Suite zu `0ff3c8b` hatte 2 FAILs in 41c. Ursache: Jedes `project`-Event während Play ließ `World.syncFromModel()` die Scene-Props neu kopieren und setzte damit die Schwerkraft aus `Set gravity` auf die gespeicherten 980 zurück; der zweite FAIL (Walker 0,11 px in der Kiste) war nur die Folge – die geschobene Kiste fiel und flog in X neben dem Walker her. Fix: `World.setSceneProp()` merkt sich, was der Lauf selbst an der Scene gesetzt hat, und `syncFromModel` legt es wieder darüber. Unit-Test liest das Modell mitten im Lauf neu (ohne Fix rot), 41c erzwingt direkt nach Play ein `project`-Event (gegen den alten Build lokal beide Checks rot, wie in CI). - **`d931e66` – flatternder Test:** Die Suite zu `328f978` war rot in 41b (Bounce), `peaks: [61.8, 37.9]`. Der Check suchte Landungen über „Ball näher als 1 px am Boden“; der Ball landet mit ~9 px pro Frame, ob ein gezeichneter Frame das trifft, hängt an der Phase zwischen zwei Physik-Schritten. CI hat die erste Landung verpasst und den zweiten Abprall als ersten gelesen – die Physik selbst stimmte (Verhältnisse 0,62/0,61 bei Bounciness 0,8). Der Check sucht jetzt Umkehrpunkte. Gegenprobe am nachgebauten Sprung über 50 Phasen: alt 15/50 grün, neu 50/50; lokal 3 Läufe `GM_STEPS=39,40,41` grün mit 99,8 → 61,8 → 37,9 → 23,2. ### Offen / Folge - #150 (umgeschrieben): Move-and-Slide entlang der Kontaktnormale mit Friction, Ausgänge hit/normal, ohne Stufen und ohne Character-Controller. - Nebenbefund, nicht angefasst: `Move` mit Kollision bewegt ein Objekt **ohne eigenen Collider** gar nicht (schon vor #147, in beiden Systemen). Doku: Wiki *Physics* (neu: *Moving bodies from a graph*, Schieben), *Behaviors*, *Colliders*, *Architecture*, *Development*; Check-Summe 1055.
admin moved this to Done in Development on 2026-09-18 21:21:13 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#147