On start during play #42

Closed
opened 2026-09-12 15:03:58 +02:00 by meleki · 1 comment
Owner

Ein im Play neu angelegter On start-Node feuert nicht für Behaviors, die schon laufen.

Stand: seit der Graph im Play bearbeitbar ist, wirken Änderungen ab dem nächsten Frame — nur On start nicht, weil der Start schon vorbei ist.

Abzuklären: nachträglich feuern (einmal pro laufender Instanz) oder bewusst so lassen und im Editor darauf hinweisen.

EDIT auch noch abzuklären: Wann feuert On start:

  • nur beim ersten Frame?
  • muss das behavior enabled sein?
  • wenn ein behavior später enabled wird, feuert On start dann noch einmalig?

Übernommen aus todo-notes/on-start-during-play.md beim Umzug auf das Issue-System (2026-09-12).

  • Angelegt: 2026-09-11 · bf41919 — Add todo notes for the next round of features, gaps and upkeep
  • Zuletzt geändert: 2026-09-12 · 11c900c — Drop the per-list item declaration; every item carries its own kind
  • Gemeldet von: Claude (Assistent)
Ein im Play neu angelegter `On start`-Node feuert nicht für Behaviors, die schon laufen. Stand: seit der Graph im Play bearbeitbar ist, wirken Änderungen ab dem nächsten Frame — nur `On start` nicht, weil der Start schon vorbei ist. Abzuklären: nachträglich feuern (einmal pro laufender Instanz) oder bewusst so lassen und im Editor darauf hinweisen. EDIT auch noch abzuklären: Wann feuert `On start`: - nur beim ersten Frame? - muss das behavior enabled sein? - wenn ein behavior später enabled wird, feuert `On start` dann noch einmalig? --- *Übernommen aus `todo-notes/on-start-during-play.md` beim Umzug auf das Issue-System (2026-09-12).* - **Angelegt:** 2026-09-11 · `bf41919` — Add todo notes for the next round of features, gaps and upkeep - **Zuletzt geändert:** 2026-09-12 · `11c900c` — Drop the per-list item declaration; every item carries its own kind - **Gemeldet von:** Claude (Assistent)
meleki added the todo-note label 2026-09-12 15:03:58 +02:00
Author
Owner

Abgeschlossen mit 6141d07 (Wiki e3e65b9)

Befund zu den drei Fragen aus der Notiz

Frage Gemessen
Feuert On start nur beim ersten Frame? Nein, beim Entstehen der Instanz (syncInstances), noch vor dem ersten On update derselben Instanz. Das passiert beim Weltstart, beim Spawn und beim ersten Einschalten eines versteckten Screens.
Muss das Behavior enabled sein? Ja, es selbst und alle Eltern (isHandleEnabled), im Editor-Lauf zusätzlich "run in editor".
Später enabled, feuert es einmalig? Beim ersten Einschalten ja, danach nie wieder: Aus/Ein friert die Instanz nur ein (enabled.test.ts "frozen again, state kept").

Der eigentliche Fehler: ein im Play neu eingefügter On start feuert an einer laufenden Instanz nie, weil OnStart nach dem Instanz-Start nicht wieder abgefragt wird (der Interpreter sieht den Node zwar sofort). Entscheidung: so lassen, im Wiki (Behaviors, Absatz Lifecycle) als Grenze festgehalten.

Gebaut: On enable, On disable, On destroy

Reihenfolge pro Instanz: On start -> On enable -> On update ... -> On disable -> On destroy.

  • On enable: direkt nach On start im selben Pulse, und jedes Mal, wenn das Behavior wieder wirksam an ist.
  • On disable: in dem Frame, in dem es wirksam aus geht, auch wenn nur ein Elternteil schaltet. Die Instanz bleibt eingefroren (Variablen, Timer, States).
  • On destroy: wenn das Entity die Welt verlässt (Destroy-Node, Kind eines zerstörten Objekts) und beim Stop/Restart (Entscheidung: Stop zählt als Destroy). War es noch an, geht On disable voraus. Ein Restart ist damit On disable -> On destroy -> (neue Welt) On start -> On enable.

Mechanik (BehaviorSystem.ts): jede Instanz merkt sich active; switched() vergleicht pro Frame und feuert die Flanke. reap() am Frame-Ende und am Sync-Anfang gibt zerstörten Entities die Abschiedsereignisse, stop() allen Instanzen vor dem Abbau.

Benannte Grenzen

  • Der Frame, der zerstört, läuft für die Instanz zu Ende: On key down -> Destroy(Owner) liefert update, update, disable, destroy (im Test festgenagelt, war schon so).
  • Aus und wieder an innerhalb eines Frames per Graph-Code ist keine Flanke: keines der beiden Events.

Beweis

  • ./check.sh: === CHECK EXIT 0 ===, 837 Tests (vorher 831; sechs neue in behavior-events.test.ts).
  • e2e Module 17 + 18 (Editor-Run, Play/Pause): ALL PASSED - 37 checks, Bundle nach der letzten src/-Änderung gebaut.
  • Fünf Gegenproben, jede beißt an ihrer Stelle: Flanke abgeklemmt, On disable auch bei schon-aus, kein Abschied beim Stop, kein On enable nach On start, kein Reap am Frame-Ende.
  • Voller Lauf und die drei Spiele: CI nach dem Push.

Doku: Wiki Behaviors (Node-Liste, Lifecycle), Containers (Screens), Concepts (Enabled).

## Abgeschlossen mit `6141d07` (Wiki `e3e65b9`) ### Befund zu den drei Fragen aus der Notiz | Frage | Gemessen | |---|---| | Feuert `On start` nur beim ersten Frame? | Nein, **beim Entstehen der Instanz** (`syncInstances`), noch vor dem ersten `On update` derselben Instanz. Das passiert beim Weltstart, beim Spawn und beim ersten Einschalten eines versteckten Screens. | | Muss das Behavior enabled sein? | Ja, es selbst *und* alle Eltern (`isHandleEnabled`), im Editor-Lauf zusätzlich "run in editor". | | Später enabled, feuert es einmalig? | Beim ersten Einschalten ja, danach nie wieder: Aus/Ein friert die Instanz nur ein (`enabled.test.ts` "frozen again, state kept"). | **Der eigentliche Fehler:** ein im Play neu eingefügter `On start` feuert an einer laufenden Instanz nie, weil `OnStart` nach dem Instanz-Start nicht wieder abgefragt wird (der Interpreter sieht den Node zwar sofort). **Entscheidung: so lassen**, im Wiki (*Behaviors*, Absatz *Lifecycle*) als Grenze festgehalten. ### Gebaut: `On enable`, `On disable`, `On destroy` Reihenfolge pro Instanz: **`On start` -> `On enable` -> `On update` ... -> `On disable` -> `On destroy`.** - `On enable`: direkt nach `On start` im selben Pulse, und jedes Mal, wenn das Behavior wieder wirksam an ist. - `On disable`: in dem Frame, in dem es wirksam aus geht, auch wenn nur ein Elternteil schaltet. Die Instanz bleibt eingefroren (Variablen, Timer, States). - `On destroy`: wenn das Entity die Welt verlässt (`Destroy`-Node, Kind eines zerstörten Objekts) **und beim Stop/Restart** (Entscheidung: Stop zählt als Destroy). War es noch an, geht `On disable` voraus. Ein Restart ist damit `On disable -> On destroy -> (neue Welt) On start -> On enable`. Mechanik (`BehaviorSystem.ts`): jede Instanz merkt sich `active`; `switched()` vergleicht pro Frame und feuert die Flanke. `reap()` am Frame-Ende und am Sync-Anfang gibt zerstörten Entities die Abschiedsereignisse, `stop()` allen Instanzen vor dem Abbau. ### Benannte Grenzen - Der Frame, der zerstört, läuft für die Instanz zu Ende: `On key down -> Destroy(Owner)` liefert `update, update, disable, destroy` (im Test festgenagelt, war schon so). - Aus und wieder an innerhalb eines Frames per Graph-Code ist keine Flanke: keines der beiden Events. ### Beweis - `./check.sh`: `=== CHECK EXIT 0 ===`, **837 Tests** (vorher 831; sechs neue in `behavior-events.test.ts`). - e2e Module 17 + 18 (Editor-Run, Play/Pause): `ALL PASSED - 37 checks`, Bundle nach der letzten `src/`-Änderung gebaut. - Fünf Gegenproben, jede beißt an ihrer Stelle: Flanke abgeklemmt, `On disable` auch bei schon-aus, kein Abschied beim Stop, kein `On enable` nach `On start`, kein Reap am Frame-Ende. - Voller Lauf und die drei Spiele: CI nach dem Push. Doku: Wiki *Behaviors* (Node-Liste, *Lifecycle*), *Containers* (Screens), *Concepts* (Enabled).
admin added this to the Development project 2026-09-13 13:43:19 +02:00
admin moved this to Done in Development on 2026-09-13 13:43:53 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: meleki/feuerwerk#42