Event Lifecycle
The exact order of movie startup, per-frame, and shutdown events - prepareMovie, beginSprite, prepareFrame, enterFrame, exitFrame, endSprite, stopMovie.
Why order matters
Every Director movie is written against an implicit contract: which handler runs before which. Games initialize globals in prepareMovie, position sprites in beginSprite, animate in prepareFrame, and read results in exitFrame. Get the order wrong in an emulator and logic silently corrupts. This page states the documented order; native verification status is tracked in Native stage, input, and timing.
Movie startup
prepareMovie
beginSprite (for sprite spans present in the first frame)
prepareFrame (before the first frame draws)
startMovie
[first frame renders]
enterFrame
...normal frame cycle continuesprepareMovie: first event. No sprites exist yet; the stage has not drawn. Initialize globals, parse startup parameters, install alert hooks.beginSprite: fired as the playhead enters each sprite span; behavior instances are created just before delivery. In frame 1 this lands afterprepareMovie, beforeprepareFrame.prepareFrame: last stop before drawing; state changes here affect the imminent render.startMovie: after the first frame is prepared; the classic "movie is ready" hook (Director 4 code often has ONLY this).
Every frame
beginSprite (only for spans that START this frame)
stepFrame (to every object in the actorList)
prepareFrame (behaviors, frame script, movie script)
[sprites drawn; stage updates]
enterFrame
[tempo wait, idle events, mouse/key events dispatched while waiting]
exitFrame
endSprite (only for spans that END this frame)
[playhead moves]Facts per event:
| Event | Received by | Notes |
|---|---|---|
beginSprite | New sprite's behaviors, then normally routed | Once per span entry. Calculated properties (e.g. rect) may be unready; go, play, updateStage are disabled inside it. |
stepFrame | actorList objects only | Also fires on every updateStage(). Engine-dispatched; cheaper than message broadcast. |
prepareFrame | Sprite behaviors, frame script, movie script | Runs before drawing. The place to move sprites so the user never sees the pre-move state. |
enterFrame | Sprite behaviors, frame script, movie script | Runs after drawing. A frame script's enterFrame shadows the movie script's for that frame. |
idle | Frame script and movie script only | Fires repeatedly while Director waits out the tempo. Frequency capped by the idleHandlerPeriod (default 0 = as often as possible). Keep handlers tiny. |
exitFrame | Sprite behaviors, frame script, movie script | Last event in the frame. go to the frame here creates the idle loop that most movies live in. |
endSprite | Ending sprite's behaviors | Once per span exit; instance is destroyed after. |
Mouse and keyboard events are delivered in the waiting window between enterFrame and exitFrame (and during idle time generally). They are not synchronized to a specific point in the frame cycle; see Input events.
Movie shutdown
endSprite (for all live sprite spans)
stopMoviestopMovie fires when playback halts or the movie is replaced by go to movie. On a cross-movie jump, the outgoing movie gets endSprite+stopMovie, then the incoming movie runs its full startup sequence. Globals, actorList, timeout objects, and windows persist across the jump (see Pitfalls).
updateStage() inside a handler
_movie.updateStage() redraws immediately without advancing the playhead:
caller handler (paused mid-execution)
stepFrame (actorList)
[stage redraw]
caller handler continuesIt does not fire prepare/enter/exitFrame. Code uses it for progress bars and blocking animations inside repeat loops. updateStage is disabled inside beginSprite/endSprite.
go, play, and re-entry
go to frame Xinside a handler finishes the current handler first; the head then moves: current frame getsexitFrame(andendSpritefor spans ending), target frame gets the entry half of the cycle (beginSprite,prepareFrame, ...).go the framere-runs the same frame's cycle without span changes (nobeginSprite/endSprite, since no span boundary is crossed).- Navigation is deferred, not immediate: statements after
goin the same handler still execute. (play donebehaves likewise.) - Tight loops on one frame are the idiom for "game loop"; per-frame work belongs in
exitFrame/prepareFramehandlers of that frame.
Timeout and network callbacks
Timeout handler messages and net-operation completions are delivered between frame events on the main thread (never preemptively during another handler). A blocked handler (long repeat loop) delays everything: rendering, input, timeouts, sound cues. The single-threaded model is a compatibility guarantee old code relies on: no handler ever observes another handler running mid-statement.
Test checklist for implementers
- Movie start:
prepareMovie->beginSprite(frame-1 spans) ->prepareFrame->startMovie. - Frame N->N+1 with a span starting at N+1: old frame
exitFrame-> newbeginSprite->stepFrame->prepareFrame->enterFrame-> ... ->exitFrame. - Span ending at N:
endSpriteafter N'sexitFrame, before N+1'sbeginSprite. updateStage()triggersstepFrame+ redraw only.beginSpriterestrictions:rectunready,go/play/updateStageinert.idleonly reaches frame/movie scripts.- Cross-movie jump ordering and state persistence.