Macromedia Director: Stepframe and Me
Previously I blogged about using Stepframe instead of EnterFrame with sprites and I discussed the why and how of making it work.
After using it a bit I have an update to explain a tick to using it.
The trick is to make sure that when adding to the Actorlist, that “me” is a behavior instance. Check this out. When a behavior is started, “me” is a behavior instance:
On Beginsprite me
put me
end
result:
-- < offspring "behaviorName" 4 307f148>
While the numbers at the end may vary, that result tells you that “me” is an instance of the behavior called “behaviorName”. If you’re not used to working with instance variables like this, then you should read up on them because they are pretty handy.
Likewise, in a MouseUp() function you’ll get the same result:
on MouseUp me
put me
end
result:
-- < offspring "behaviorName" 4 307f148>
However, if you call a function in a sprite’s behavior from another script, you have to look out. I often call behavior functions inside of sprites externally like so:
-- From code in sprite 1:
on mouseup me
sprite(5).startfade()
end
-- From code in sprite 5:
on startfade me
put me
end
result:
-- (sprite 5)
Notice that the value “me” changed. It’s not an instance (AKA offspring), it’s a sprite object. And because it’s a sprite object, it behaves differently if it’s added to The Actorlist. Specifically, if you add a sprite object to the actorlist, then every behavior attached to the sprite will get a Stepframe message every single frame. However, if the behavior’s instance is added to Actorlist, only that behavior will get it’s StepFrame handler called.
Having all the behaviors called really only becomes a problem if you’ve got two or more behaviors on one sprite that both want to use StepFrame, because if one behavior adds a sprite object to the Actorlist, other behaviors will start getting StepFrame events when they’re not expecting it. In fact, if two behaviors on one sprite both add sprite objects to the Actorlist, each behavior will get their Stepframe handler called twice per frame. Once that happens, it’s possible for really strange things to happen, which I’ll explain below. But for now, let’s take a look at how I fixed it.
How to solve the problem
I solved the problem by saving my behavior instance for use later, like so:
property MeObj
on beginsprite me
MeObj = me
end
on startfade me
-- Notice here I'm using "MeObj" instead of "Me"
add the actorlist, MeObj
end
on stopfade me
deleteone the actorlist, MeObj
end
What’s happening above is that in Beginsprite I’m storing “me” in the property MeObj. I’m doing this here because we know that when Beginsprite is first called, “me” is the behavior instance, and not a sprite object.
Later, in functions that may or may not be called externally, I use MeObj instead of Me to add to the Actorlist. This insures that the behavior instance is being added and not the sprite object. Likewise, MeObj is used when deleting from the Actorlist as well. Using this technique, the only behaviors that add themselves to the Actorlist will actually have their StepFrame handlers called.
How the problem surfaced for me
I had two different behaviors on one sprite that both used Stepframe. Each one would keep a local property called InActivated to track when it had added itself to the Actorlist so that it was not possible for the behavior to add itself multiple times. However, I was not using the MeObj technique described above, and I ran into the following problem.
- sprite(1)’s behaviorA adds (sprite 1) to the actorlist because it is called from another sprite, and turns it’s IsActivated property on.
- sprite(1)’s behaviorB is triggered seperately and adds < offspring "behaviorb" > to the actorlist and turns it’s own IsActivated property on.
- sprite(1)’s behaviorA gets the Stepframe event where me = (sprite 1) and it works as expected.
- Because (sprite 1) being in the Actorlist causes all the behaviors to get a StepFrame event, sprite(1)’s behaviorB gets the Stepframe event where me = (sprite 1).
- BehaviorB is done, so it calls “deleteone the actorlist, me” and clears his IsActivated property. Except Me does not equal < offspring "behaviorb">, it equals (sprite 1).
The end result is that < offspring "behaviorB" > is still in the actorlist even though the behaviorB instance thinks it’s done (it’s IsActivated property is cleared), and behaviorA has stopped getting stepframe events even though it’s not done (and still has it’s IsActivated property set).
It’s very complex to be sure, and it took me a bit of debugging and carefully studying all the values involved before I cound figure out what was going on.


I'm Hanford Lemoore. My parking skills are unparalleled.






November 3rd, 2006 at 5:26 am
Use sendSprite(5, #startFade) instead, and the problem will go away.
If the sprite has no on startFade handler, sprite(5).startFade() will cause a script error, but sendSprite(5, #startFade) will fail silently.