Adding Behaviors to 3D Models
June 7, 2005
by James Newton
Source files: PickAction.sit (Macintosh) | PickAction.zip (Windows)
The movie above is scarcely spectacular. If you click on the rotating Box model, the background color of the 3D sprite changes, and a message is displayed telling you which face of which mesh has been clicked. Wow.
The big deal is that the code that does this is attached to the Box model itself, in the same way that a behavior is attached to a 2D sprite.
If you thought that you can't attach behaviors directly to models, then you are right. Almost. What you can do is add script instances to the userData
list which is a property of every 3D node.
Behaviors have four main advantages over the script-instance-in-a-userData
-list approach:
- You can drop a behavior directly onto a sprite
- You can set the parameters of the behavior without writing any code
- The built-in
spriteNum
property allows you to obtain a pointer to the sprite the behavior is attached to - Director dispatches mouse and keyboard events automatically
You'll see how to work around (or to live with) these limitations in what follows.
Adding a behavior to the userData
list
Here's the handler that creates the Box model, and which attaches an instance of the script("Model Instance") to the userData
list. As you can see, adding the instance requires only a couple of code. If parameters were required, they could be set in the on new()
handler, or in a separate on init()
handler if you prefer to work that way. If you are prepared to get your braincells dirty by working in 3D Lingo, the loss of drag and drop functionality and the joys of the getPropertyDescriptionList()
handler are not going to upset you.
on beginSprite(me) vScene = sprite(me.spriteNum).member vScene.resetWorld() -- Create a box model vResource = vScene.newModelResource("Box", #box) pModel = vScene.newModel("Box", vResource) -- Add a "behavior" to the model vInstance = script("Model Instance").new() pModel.userData.addProp(#instance, vInstance) end beginSprite
Dispatching events
Attaching an instance to the userData
list for a model not in itself enough to trigger event handlers when the user clicks on the model. You need to add a behavior to the 3D sprite that dispatches events to the appropriate userData
list. You'll find a complete Pick Action behavior in the download source movie. Here's a simplified which deals only with mouseUp
events:
on mouseUp(me) vSprite = sprite(me.spriteNum) vLeft = vSprite.left vTop = vSprite.top -- Determine which 3D model is under the mouse tSpriteLoc = point(the mouseH - vLeft, the mouseV - vTop) tModelData = vSprite.camera.modelsUnderLoc(tSpriteLoc, 1, #detailed) if not tModelData.count then -- There are no models under the mouse exit end if -- Retrieve the userData list for the model under the mouse tModelData = tModelData.getLast() -- only 1 model is asked for tModel = tModelData.model tUserData = tModel.userData -- Call the userData list, sending a pointer to this sprite and -- the picking data. NOTE: since D8.5 it is possible to "call" a -- property list. call(anEvent, tUserData, vSprite, tModelData) end mouseUp
The Pick Action behavior in the download files is more sophisticated, and sends #mouseDown, #mouseUp, #rightMouseDown and #rightMouseUp
events, as required.
Obtaining a pointer to the sprite
Here's a simplifed version of the "behavior" that is added to the Box model's userData
list:
on mouseUp(me, a3DSprite, aModelData) vMember = a3DSprite.member vColor = rgb(random(5)-1, random(5)-1, random(5)-1) * 51 vMember.bgColor = vColor end mouseUp
The me
handler points to the "behavior" itself, but you can't get at the sprite by using sprite(me.spriteNum)
, so the sprite has to be passed in as a separate parameter. The picking details for the model are passed in as a third parameter. This will be a property list similar to the following:
[#model: model("Box"), #distance: 148.3333, #isectPosition: vector( 23.0958, 6.8110, -12.9864 ), #isectNormal: vector( 0.9848, 0.0000, -0.1736 ), #meshID: 2, #faceID: 1, #vertices: [vector( 20.2790, 25.0000, -28.9614 ), vector( 28.9614, -25.0000, 20.2790 ), vector( 20.2790, -25.0000, -28.9614 )], #uvCoord: [#u: 0.3244, #v: 0.0394]]
Whether you need some or all of this data, the Pick Action behavior has already prepared it for you.
Conclusion
In conjunction with the Pick Action behavior, adding one or more script instances to the userData
list of your 3D models gives you more precise control over your 3D world. The technique is simple and robust. Have fun with it!
Source files: PickAction.sit (Macintosh) | PickAction.zip (Windows)
Copyright 1997-2025, Director Online. Article content copyright by respective authors.