The "Dynamism" Movie Script
Every project in which you want to create WFS dynamic sprites must have a copy of the "Dynamism" movie script in a Cast. Also, you must edit a line of this script to set the number of dynamic sprite channels available to WFS. Please read the below section on the Dynamic Channel Manager for the where/how/why of this edit.
If you want to create WFS dynamic sprites, you may not need to call any handlers in "Dynamism" at all except the Destructors. Please check out the documentation on the "Script Writer" handlers for the easiest, most powerful way to create dynamic multi-sprites, elements, and families of multi-sprites. They are easy to use and may do all you want to do.
You may want to use handlers in "Dynamism", however. Your primary usage of the Dynamism handlers will probably involve the destructors, documented here. Although WFS does garbage collection of dynamic sprites at the end of the movie, you may want to destroy elements or multi-sprites or families of multi-sprites before the movie is over. In that case, you will want to look at
Dynamic Channel Manager
What sprite channels are used for dynamic sprites?
WFS provides an API into the Dynamic Channel Manager.
Dynamic sprites are created by puppeting empty sprite channels (or using makeScriptedSprite, in DMX 2004 and later), giving the channel a member (either by creating the member or using an already existing one), and attaching and initializing behaviors on the fly.
If you've done any puppeting of channels, you know that channels that have a drag and drop sprite in them at any point in the movie do not work right as puppeted channels. In other words, you encounter problems if you mix dynamic and static sprite channels. In particular, there are problems attaching behaviors to sprites in channels that are static (drag and drop) at any point during the movie. This is because when you create a dynamic sprite, it is instantiated through all the frames of the movie until you destroy it.
How WFS solves this problem is to use channels for dynamic creation/destruction that never have a static sprite in them at any point during the movie. The "Dynamism" script partitions the Score into two blocks. The top block of channels is for static sprites. The bottom block of (higher-numbered) channels is for dynamic sprites. The Dynamic Channel Manager in the "Dynamism" script manages the channels available for dynamic creation.
How does WFS know how to draw the line between the two blocks of sprites (static and dynamic)? It doesn't know how. You have to tell it where to draw the line. How do you do this? You edit the value of gWFSLastStaticSpriteChannel in the wfsInitializeDynamism handler in the "Dynamism" script. The wfsInitializeDynamism script is shown below. It is recommended you read the comments.
gWFSLastStaticSpriteChannel = the lastChannel --EDIT THIS VALUE
gWFSNumberOfDynamicallyAllocatableChannels=the lastChannel - gWFSLastStaticSpriteChannel
As it says in the above code, you need to edit the value of gWFSLastStaticSpriteChannel. By default, you don't have any dynamic channels to play with because, by default, gWFSLastStaticSpriteChannel is set to the lastChannel, ie, by default WFS assumes all channels are static.
If the Score of your movie looked like the above, then you would set gWFSLastStaticSpriteChannel to 4. The WFS Dynamic Channel Manager would then use channels 5 and higher for dynamic sprites.
Max 1000 Channels in Director 8 - MX 2004
Director 8 - MX 2004 permits a maximum of 1000 simultaneously instantiated sprites. The number of channels can exceed 1000, but the maximum number of simultaneously instantiated sprites is 1000. You generally want to be well below that, for performance reasons, but 1000 is your absolute max.
How do you change the total number of channels in your movie? The below graphic shows you how:
The Dynamic Channel Manager will use channels gWFSLastStaticSpriteChannel+1 to the lastChannel for dynamic sprites. I normally set the total number of channels in a movie to 1000 if I'm using dynamic sprites.
How sprite channels are allocated by the Dynamic Channel Manager
Before a dynamic sprite is created, the Dynamic Channel Manager checks to see if there is an available dynamic channel. If there are any, the Dynamic Channel Manager allocates the first available one, ie, the lowest-numbered available dynamic channel. So, for instance, the first channel it allocates will always be gWFSLastStaticSpriteChannel+1, presuming you have edited gWFSLastStaticSpriteChannel so that there are some dynamic channels to allocate (see above).
This is kind of important to understand. Why? You need a sense of where your sprites are in the Score for debugging purposes, for one thing. Also, sometimes we write handlers that have algorithms that do things to the sprite in channel 'spritenum - 1' or something like that, ie, we assume that sprites are contiguous in the Score because they are. But when you use that sort of logic concerning WFS dynamic sprites, it doesn't always work.
For instance, if you make a dynamic copy of a multi-sprite (using the handlers in the "Script Writer" script) after you have created and destroyed more than 1000 sprites, elements that were contiguous in the static model you used to generate the dynamic multi-sprite may no longer be contiguous in the Score. They'll work fine in the WFS code, but they might not be contiguous in the Score, perhaps, because, when creating dynamic sprites, the Dynamic Channel Manager allocates the first available one, ie, the lowest-numbered available dynamic channel (a sorted queue).
What remains invariant, then? Well, if you use the "Script Writer" handlers to create multi-sprites, the elements are created in a certain order. So that if, in a static multi-sprite, a particular sprite was element 5, it will still be element 5 of a dynamic version of the multi-sprite. In other words, it will still have spritenum pWFSElementList (unless you delete lower elements), where pWFSElementList is maintained by the Manager. wfsGetElementList returns a duplicate of pWFSElementList, a multi-sprite's list of spritenums of elements.
Various WFS handlers make calls to the wfsGetUnusedChannel private handler in the "Dynamism" script to obtain a channel in which to create a dynamic sprite. You shouldn't have to make calls to this handler since WFS does it for you, but you should understand how allocation works. wfsGetUnusedChannel returns a channel number or 0 if there are no channels available. All dynamically created sprites in WFS have to go through the Dynamic Channel Manager to obtain a channel.
Various WFS destructor handlers also make calls to the private handler wfsReturnChannel(theChannel) when dynamic sprites are destroyed. This returns the channel to the Dynamic Channel Manager so the channel can be reused.
When you create a static multi-sprite, the elements find their manager on beginSprite. They can find their manager because they assume that their manager is the first manager in the Score that is above them in the Score. You can use wfsAddElementToManager thereafter, ie, you can change the manager to be some other manager after the elements become instantiated, so the manager doesn't have to be above the elements in the Score once the element's beginSprite handler has run. But a static element does have to be below its initial manager in the Score.
Dynamic elements don't assume that their manager is above them in the Score. Why not? Well, given that the Dynamic Channel Manager allocates the first available channel, ie, the lowest-numbered available dynamic channel, after your movie runs a while and creates and destroys sprites, the first available channel could be anywhere among the dynamic channels. So the beginSprite handler operates a bit differently for dynamic elements. They are assigned a manager rather than finding their own manager. This is done with a call to wfsAddElementToManager. Notice also that when you use wfsWriteElement, the output handler requires you tell it which Manager to add the element to. Dynamic elements can't find their manager like static ones can.
Limitations of WFS Dynamic Sprites
There are certain properties that the "Script Writer" handlers do not read when they write code to copy sprites. Over time, and with your feedback, this list will be shortened.
In WFS, when a sprite is created using the wfsCreateSprite handler, the parameters fed to wfsCreateSprite are these: [memberNameOrNumber, castNameOrNumber, ink, blend, width, height, locH, locV, doNotCreateNewMember].
If you feel there should be more properties read, let me know, please. Of course, the behaviors are dealt with thoroughly, but the properties of the member and the sprite are not exhaustively read.
Also, if you use the buttons circled below in the Property Inspector, the "Script Writer" behaviors will not pick up these properties.
These are relatively easy to deal with, however. For instance, the button above that makes text sprites editable can be done otherwise. You can attach a behavior to the sprite, instead, that sets the 'editable' property.
sprite(whichsprite).editable=1 sets a text sprite as editable, and setting that property to 0 makes it non-editable
WFS contains the "Drag Element" behavior, so you won't need the button above that makes sprites moveable. And the "Drag Element" behavior is better since you can constrain the movement in a configurable way.
sprite(whichsprite).trails=1 makes a sprite leave trails. Setting that property to 0 gets rid of trails.
sprite(whichsprite).flipV=1 is the same as clicking the 'flip vertical' button above.
sprite(whichsprite).flipH=1 is the same as clicking the 'flip horizontal' button above.
sprite(whichsprite).rotation=90 is the same as specifying 90 degrees in the rotation text box in the property inspector.
sprite(whichsprite).skew=5 is the same as specifying a 5 percent skew.
And so on: for each button or text box you can set in the Property Inspector, there's an equivalent Lingo command you can use; the Lingo way to do these things will be picked up by the WFS Dynamic routines because you'll have attached a behavior to the sprite, and WFS copies behaviors perfectly.
Please let me know if there are improvements you feel are warranted in these areas in WFS. WFS is the first tool that makes dynamic sprite creation/destruction relatively easy. So I'll need your feedback on improving it.
Dynamic Sprite Creation Bugs
This section has not been updated concerning makeScriptedSprite/removeScriptedSprite. This section discusses dynamic sprite creation via puppetSprite in Director 5 to Director MX.
The destructors function like their names suggest. Though WFS does garbage collection of dynamic sprites at the end of the movie, you may want to destroy elements and/or multi-sprites and/or families of multi-sprites when you are done with them, before the end of the movie. When dynamic sprites are destroyed by the destructors, their channels are returned to the WFS Dynamic Channel Manager and they can be reused by the Dynamic Channel Manager.
You shouldn't have to call any of these if you use the Script Writer handlers, which are more powerful than these constructors.The first three of these constructors are called by handlers generated by the Script Writer handlers. The last three are not called anywhere in the WFS code.
You shouldn't have to call any of these if you use the Script Writer handlers. The wfsAttachBehavior handler is a general, powerful handler to attach and initialize any behavior to any sprite, dynamic or otherwise. The rest of the attacher handlers attach WFS behaviors to sprites and initialize the behaviors. They initialize the getPropertyDescriptionList properties and they run the beginSprite handler, if the behavior has one (WFS behaviors usually have a beginSprite handler). You can use the Attachers to attach WFS behaviors to both static and dynamic sprites.
You shouldn't have to call any of these if you use the Script Writer handlers. If you use the Dynamic Attachers, then use wfsRemoveScriptAndRunEndSprite to remove the behavior.
These handlers return information about the current state of the Dynamic Channel Manager. Read the 'Dynamism' documentation for a discussion of the Dynamic Channel Manager.