DDirectorWikiDirector & Lingo Encyclopedia

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.

lingo
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
end
  • me is the behavior instance.
  • me.spriteNum (or the spriteNum of me) is the channel number the instance is attached to. Frame behaviors have spriteNum = 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.

lingo
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"
end

Recognized #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

lingo
-- 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 instanceChild object
Created byPlayback head entering the sprite spanExplicit new()
Destroyed byPlayback head leaving the span (endSprite)Losing all references
Tied to a spriteAlways (me.spriteNum)Only if you store one
Receives sprite/mouse eventsAutomaticallyNever (unless you forward)
Receives stepFrameNo (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:

lingo
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

lingo
-- "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
end

Note 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.