Event handlers called every frame in a Director movie

Every frame Director calls an number of handlers. To avoid script errors the order in which these handlers in called is important.

movieprepareMovie()First frame of movie
framenew() + beginSprite()First frame of sprite
sprite(1..n)new() + beginSprite()First frame of sprite
actorList[1..n]stepFrame()Every frame and updateStage()
sprite(1..n)prepareFrame()Every frame
frameprepareFrame()Every frame
After display is updated
moviestartMovie()First frame of movie
sprite(1..n)enterFrame()Every frame
frameenterFrame()Every frame
frameidle()Every frame
sprite(1..n)mouseWithin()Every frame when mouse is over sprite
sprite(1..n)exitFrame()Every frame
frameexitFrame()Every frame
moviestopMovie()Last frame of movie
frameendSprite()Last frame of sprite
sprite(1..n)endSprite()Last frame of sprite

It is better to use the enterFrame() handler to modify sprites than the prepareFrame() handler. The reason is that it is about 10% faster. I suspect that code in stepFrame() handlers is also slower than the enterFrame() handler but I have not tested it.

The drawback of the enterFrame() handler is that the display is updated before this hanlder is called. Normally this is only a problem in the first frame of a sprite. The problem can be fixed by calling the enterFrame() handler from the beginSprite() handler. As illustrated here:

on beginSprite me

on enterFrame me
  -- Animate

There is one problem with this method. Sprites with a higher number than the current sprite may not be fully initialized when enterFrame() is called from beginSprite(). This can be fixed by moving the call to enterFrame() from beginSprite() to prepareFrame(). As illustrated here:

property pInitialized

on prepareFrame me
  if not pInitialized then
    pInitialized = TRUE
  end if

on enterFrame me
  -- Animate

Since prepareFrame() is called every frame this code run a little bit slower than calling enterFrame() from beginSprite(). Normally this will not be any problem at all.


This handler is called every frame as long as the mouse is over the sprite. If a sprite is only animating in this condition it is a good idea to move code from enterFrame() to mouseWithin().


The stepFrame() handler was added to Director a very long time ago and it is not used a lot anymore. The prepareFrame() and enterFrame() handlers are used instead. The stepFrame() handler can be used to optimize the speed of Director movies by removing unnessary calls to prepareFrame() and enterFrame(). In this example stepFrame() is only called when the sprite is animating.

This optimazation benefits movies with many behaviors in the same frame, but is not relevant if there is only a few behaviors in the same frame.

property pChannel
property pInside

on beginSprite me
  pChannel = sprite(me.spriteNum)

on endSprite me

on stepFrame me
  if pInside then
    pChannel.blendLevel = max(pChannel.blendLevel - 10, 0)
    if pChannel.blendLevel = 0 then removeStepFrame(me)
    pChannel.blendLevel = min(pChannel.blendLevel + 10, 255)
    if pChannel.blendLevel = 255 then removeStepFrame(me)
  end if

on mouseInside me
  pInside = TRUE

on mouseOutside me
  pInside = FALSE

on addStepFrame me
  -- Modifying the actorList inside a stepFrame() handler has some bad side effects. There
  -- is a work around this this, which is documented elsewhere.
  if not (the actorList).getPos(me) then (the actorList).add(me)

on removeStepFrame me
  -- Modifying the actorList inside a stepFrame() handler has some bad side effects. There
  -- is a work around this this, which is documented elsewhere.
  (the actorList).deleteOne(me)

The stopMovie() handler is not the last handler called when a movie stop. First the stopMovie() handler is called and then the endSprite() handlers for behaviors is called. So you must careful not to have code in the stopMovie() handler, that will cause code in the endSprite() handlers to fail.

on stopMovie
  -- Send endSprite() events
  sendSprite(0, #endSprite)
  -- Remove behaviors from all sprites, to prevent endSprite() events later
  sprite(0).scriptInstanceList = []  
  repeat with c = 1 to the lastChannel
    sprite(c).scriptInstanceList = []  
    sprite(c).visible = TRUE
    sprite(c).puppet = FALSE
  end repeat
  -- Clear the actorList
  the actorList = []
  -- Call new stopMovie handler
  -- Prevent code in calling handler to be executed. The may fix the bug
  -- described here

on newStopMovie
  -- Add clean up here...