A behavior object carries a "Run in editor" switch next to Enabled. When it is on, the behavior ticks outside of Play and works on the saved model directly - Unity semantics: what it moves is a real change, autosaved and not undoable. Input stays with the editor, so On key never fires while typing. The editor run never bakes placed containers into the model, since that would silently drop their instanceEdits. syncToModel reports whether it wrote anything, and the dirty flag is only raised on change - otherwise a behavior moving something every frame would trigger ~60 saves a second.
6.0 KiB
ein toggle bei einem behavior object in einer scene (passender name fehlt mir noch):
- wenn der toggle aktiviert ist, soll das behavior außerhalb des play modes trotzdem laufen (sprich immer)
- das behavior ist natürlich nicht aktiv wenn die scene nicht geladen ist wo sich das behavior befindet (sprich genauso wie im play mode, nur ohne play mode)
Umgesetzt (2026-09-09). Der Schalter heisst Run in editor und steht im Inspector eines
Behavior-Objekts direkt unter Enabled. Ist er an, laeuft das Behavior weiter, waehrend das
Projekt nicht spielt (src/editor/EditorRun.ts, vom Editor neben der Play-Session getickt).
Die eine Entscheidung, die der Schalter erzwingt
Play arbeitet auf einer Wegwerf-Kopie — deshalb ist Spielen fuer das gespeicherte Projekt
gefahrlos. Ausserhalb von Play gibt es diese Kopie nicht, und damit stand die Frage im Raum, was
ein laufendes Behavior ueberhaupt anfassen darf. Entschieden wurde (Rueckfrage an den User) fuer
die Unity-Semantik (ExecuteInEditMode):
Was das Behavior bewegt oder schreibt, ist eine echte Aenderung am gespeicherten Modell. Sie wird autosaved, die Panels zeigen sie — und Undo holt sie nicht zurueck.
Das macht den Schalter maechtig (ein Behavior kann Inhalt bauen oder anordnen) und ist genau der Grund, warum er standardmaessig aus ist. Der E2E-Check haelt beide Haelften fest: der Server liefert die verschobene Position aus, und nach zwei Undos ist der Schalter weg, die Bewegung nicht.
Was der Editor-Lauf bewusst nicht bekommt
| Eingaben | Tastatur und Maus bleiben beim Editor, sonst wuerde Tippen in einem Textfeld Behaviors ausloesen. On key …, On click und Is key down feuern hier nie; On start, On update, On timer und Kollisionen schon. |
| Container-Inhalt | syncFromModel schreibt den Inhalt platzierter Container als normale Objekte aus (baking) und loescht dabei deren instanceEdits — im Editor waere das eine stille, irreversible Aenderung. Der Lauf instanziiert deshalb mit bakeContainers: false. Preis: ein Behavior innerhalb eines platzierten Containers laeuft ausserhalb von Play nicht. |
| ein zweites Leben | Nur die Behaviors der geladenen Szene laufen, und nur im Edit-Modus. Play stoppt den Editor-Lauf — dort laeuft ohnehin jedes Behavior. Eine Exception im Graphen oder ein Stop game-Node beendet den Lauf und schreibt den Grund in die Notice-Zeile, statt ihn 60× pro Sekunde zu wiederholen. |
Der zweite Punkt der Notiz faellt damit von selbst heraus: die Welt wird aus der aktiven Szene gebaut, ein Behavior einer anderen Szene hat gar keine Entity. Beim Szenenwechsel wird der Lauf neu aufgebaut oder verworfen.
Kein Save-Sturm
Ein Behavior, das jeden Frame etwas verschiebt, macht das Modell jeden Frame schmutzig — 60× pro Sekunde speichern waere die naheliegende Katastrophe. Zwei Dinge verhindern das:
syncToModel()meldet jetzt, ob ueberhaupt geschrieben wurde ({structure, values}statt eines blossenboolean). Ein Behavior, das nur liest oder wartet, macht gar nichts schmutzig.setSaveStatus('dirty')emittiert nur bei Wechsel, der Autosave-Timer wird also nicht jeden Frame neu gestellt. Gemessen: 2 Speicherungen in 2 Sekunden, nicht ~120.
Ein Darstellungsfehler, den erst der Screenshot gezeigt hat
schemaForAsset liefert fuer ein Behavior COMMON_PROPS + Typschema + Variablen. Der
Object-Inspector zeigte alles ausser enabled unter der Ueberschrift VARIABLES — der neue
Schalter landete also dort, wo nur steht, was das Behavior deklariert, und die Notiz „The
behavior declares no variables." verschwand fuer immer. Beides ist repariert: die Typschema-Zeilen
eines Behaviors stehen jetzt bei Enabled, die Sektion darunter fuehrt wieder nur die Variablen.
Aufgefallen ist es nur, weil ich mir den Screenshot angesehen habe — die Checks waren zufrieden.
Ein Messgeraet statt eines geratenen Offsets
Der erste Anlauf klickte die Checkbox ueber locate('Enabled').x + 55. Das trifft nur Zeilen,
deren Label in die 64-px-Spalte passt — Run in editor ist breiter und schiebt seine Checkbox
11 px nach rechts, also ging der Klick daneben und fuenf Checks fielen um. Neu ist deshalb
__gm.inspectorField(label): es liefert die Bildschirmmitte des Controls einer Inspector-
Zeile, gefunden ueber sein Label. Damit ist jeder kuenftige Inspector-Check unabhaengig von der
Labelbreite.
Belegt
Acht Unit-Tests (tests/editor/editor-run.test.ts, plus einer in container.test.ts fuer das
Nicht-Backen). Gegengeprueft: dreht man den Filter auf „alle Behaviors" und die Szenen-Bedingung
weg, fallen vier von sieben um; mit bakeContainers: true faellt der Container-Test.
Dazu zehn E2E-Checks in Modul 17:
PASS a placed behavior does not run outside play mode until it is asked to
– {"running":false,"time":0,"behaviors":[]} x=0
PASS the inspector offers the switch on a behavior object, with Enabled and above the variables
– {"enabledBox":{"x":1070,"y":221},"runBox":{"x":1081,"y":253},"variables":{…,"y":509.5}}
PASS switching it on is an ordinary override on the object – {"runInEditor":true}
PASS the behavior runs although Play was never pressed
– {"running":true,"time":0.46,"behaviors":["er-logic"]} mode=edit
PASS the owner drifts on, and the moved object is the stored one – x 48.33 → 108.32
PASS what the behavior moved is saved, not just shown – stored x=308.31 (started at 0)
PASS saving stays debounced while it runs, instead of once per frame – 2 saves in 2 s
PASS taking the switch back stops the run and the object stands still – x=329.98
PASS undo takes back the switch, never the movement it caused – overrides={} x=351.65, started at 0
PASS the step leaves nothing of its own behind
Der Schritt baut sich seine eigene Kiste samt Behavior (On update → Move(owner)) statt den
Mover der Fixture zu nehmen — der laeuft ueber die Pfeiltasten, und die sieht der Editor-Lauf
absichtlich nie. Am Ende raeumt er alles wieder weg.
Screenshot 36-editor-run.