Behaviors
Writing sprite and frame behaviors - property declarations, getPropertyDescriptionList, me and spriteNum, behavior ordering, and messaging.
What a behavior is
A behavior is a script attached to a sprite span or a frame in the Score. When the playback head creates the sprite (at beginSprite), Director instantiates the behavior: each attachment becomes an independent script instance with its own property values, listed in sprite(n).scriptInstanceList.
property pSpeed
on beginSprite me
pSpeed = 5
end
on prepareFrame me
sprite(me.spriteNum).locH = sprite(me.spriteNum).locH + pSpeed
end
on mouseUp me
pSpeed = -pSpeed
endmeis the behavior instance.me.spriteNum(orthe spriteNum of me) is the channel number the instance is attached to. Frame behaviors havespriteNum = 0.- Multiple behaviors can be attached to one sprite; they receive events in attachment order, and that order is editable in the authoring tool. Compatibility note: order is significant, see Message hierarchy.
Parameterized behaviors
The authoring-time parameter dialog is driven by getPropertyDescriptionList. When a behavior is dropped onto a sprite, Director runs this handler and builds a dialog from the returned property list; chosen values are baked into the Score and assigned to the instance before beginSprite.
property pSpeed
property pSound
on getPropertyDescriptionList me
d = [:]
addProp d, #pSpeed, [#comment: "Speed (px/frame)", \
#format: #integer, #default: 5, \
#range: [#min: 1, #max: 20]]
addProp d, #pSound, [#comment: "Click sound", \
#format: #sound, #default: "click"]
return d
end
on getBehaviorDescription me
return "Moves the sprite horizontally; plays a sound on click."
end
on getBehaviorTooltip me
return "Mover"
endRecognized #format values include #integer, #float, #string, #symbol, #boolean, #member, #bitmap, #sound, #marker, #ink, and others; #range may be a min/max propList or a list of choices (rendered as a popup).
Runtime relevance for emulators: the dialog itself is authoring-only, but the authored values live in the Score data and must be applied to each instance before beginSprite fires. runPropertyDialog exists for scripted control of the same mechanism.
isOKToAttach me, spriteType, spriteNum lets a behavior veto attachment to unsuitable sprites (authoring-time only).
Events a behavior can receive
Sprite behaviors get the full sprite event set:
- Lifecycle:
beginSprite,endSprite - Frame cycle:
prepareFrame,enterFrame,exitFrame(per frame while the span is active) - Mouse:
mouseDown,mouseUp,mouseEnter,mouseLeave,mouseWithin,mouseUpOutside,rightMouseDown,rightMouseUp - Keyboard:
keyDown,keyUp(when the sprite has keyboard focus, e.g. editable text) - Custom messages via
sendSprite/sendAllSprites/call
Frame behaviors get frame cycle events plus stage-level mouse/key events that no sprite consumed.
State and communication
-- read another behavior's property on the same sprite
whatSpeed = sprite(3).getAt(sprite(3).scriptInstanceList, 1).pSpeed
-- cleaner: message the sprite
_movie.sendSprite(3, #setSpeed, 12)
on setSpeed me, v
pSpeed = v
end
-- broadcast
_movie.sendAllSprites(#pause)
-- direct call to a known instance (does NOT continue down the hierarchy)
call(#setSpeed, someInstance, 12)sendSprite delivers to all behaviors on the target sprite and then lets the message continue through the normal hierarchy (cast member script, frame script, movie script). call() targets exactly the given instance(s) with no fall-through. Both return control synchronously.
Behaviors vs child objects
| Behavior instance | Child object | |
|---|---|---|
| Created by | Playback head entering the sprite span | Explicit new() |
| Destroyed by | Playback head leaving the span (endSprite) | Losing all references |
| Tied to a sprite | Always (me.spriteNum) | Only if you store one |
| Receives sprite/mouse events | Automatically | Never (unless you forward) |
Receives stepFrame | No (uses prepareFrame etc.) | Yes, if placed in the actorList |
The two mix: behaviors frequently create child objects in beginSprite and forget them in endSprite, and a behavior can hold an ancestor object shared by many sprites.
Dynamic attachment
Score recording aside, MX 2004 allows runtime behavior manipulation:
sprite(5).scriptInstanceList.add(new(script "Hover")) -- attach at runtime
-- puppeting a channel and configuring it wholesale:
puppetSprite 5, TRUE
sprite(5).member = member "ball"
sprite(5).loc = point(200, 150)Runtime-attached instances receive events from the point of attachment on; they did not get beginSprite retroactively (their initialization is the caller's problem). This is a fidelity point emulators get wrong easily.
A complete example
-- "Drag me" behavior
property pDragging, pOffset
on beginSprite me
pDragging = FALSE
end
on mouseDown me
pDragging = TRUE
pOffset = sprite(me.spriteNum).loc - the clickLoc
end
on exitFrame me
if pDragging then
sprite(me.spriteNum).loc = point(the mouseH, the mouseV) + pOffset
end if
end
on mouseUp me
pDragging = FALSE
end
on mouseUpOutside me
pDragging = FALSE
endNote the shape: state changes happen in input handlers, position updates happen in the frame cycle, and mouseUpOutside covers the release-off-sprite case. This is idiomatic Director and survives frame-rate changes.