von dp am 23.August 98 um 17:59:07:
I don't know "the best" Z-sorting approach... other DIRECT-L listmembers have done some great work on this, and I suspect different situations would require different solutions. But if you wish to use Lingo's internal "sort" command on a list, then the following shows the skeleton of one approach. The core is a sorted propList of behavior instances in [zPos: object] format, similar to the tactic Jim Collins described. At exitFrame each sprite calculates its new XYZ position, removes its old zPos:obj entry from the zList, and then adds its new zPos:obj entry. On prepareFrame each instance then matches its position in the zList to a corresponding spriteList to find in which channel to draw its member. There are two unusual techniques here. First is the automatic registration of all similar behaviors and their sharing of common list objects. There are more examples of such behavior registration in the technotes. The second unusual technique is how each behavior can control the member and loc of a different sprite channel in the group. This latter point introduces a complication, described after the snippet. -- Z-Sort Example (behavior skeleton) -- Sprites with similar behavior find each other and -- sort their depth in the screen. -- Needs your own transforms and stresstesting. Aug 2 98 jd property spriteNum, myX, myY, myZ, myZdelta property myMember, ourZlist, ourSpriteList on beginSprite me set myMember to the member of sprite spriteNum sendAllSprites(#ZSortExample_RegisterBehaviors, [:], []) sort ourZlist -- Simple static values for illustration: set myX to the locH of sprite spriteNum set myY to the locV of sprite spriteNum end -- Called for all sprites from each sprite's beginSprite. -- All sprites will share the same z-order and sprite lists in memory. on ZSortExample_RegisterBehaviors me, zList, spriteList set ourZlist to zList set ourSpriteList to spriteList addProp ourZlist, myZ, me add ourSpriteList, spriteNum end -- Calculate new positions at the end of each frame: on exitFrame me -- Your XYZ transform operations here: set myZ to myZ + myZdelta -- Insert object reference at new position in zList: deleteAt(ourZlist, getPos(ourZlist, me)) addProp ourZlist, myZ, me end -- And then before the next frame, display new positions: on prepareFrame me set whichChannel to getAt(ourSpriteList, getPos(ourZlist, me)) set the member of sprite (whichChannel) to myMember set the loc of sprite (whichChannel) to point(myX, myY) end -- A sprite can be removed without affecting the group: on endSprite me deleteAt(ourZlist, getPos(ourZlist, me)) deleteOne(ourSpriteList, spriteNum) end -- Simple properties for illustration: on getPropertyDescriptionList me set theProps to [:] set c to "Initial Z position:" set r to [#min: -10.0, #max: 10.0] addProp theProps, #myZ, [#comment:c, #format:#float, #range:r, #default:0] set c to "Z movement:" set r to [#min: -1.0, #max: 1.0] addProp theProps, #myZdelta, [#comment:c, #format:#float, #range:r,#default:0] return theProps end (Warning: I reserve the right to have overlooked something here... it passed my quick tests, but it's hot out and I may have missed a test. Use your own judgment and experience, thanks.) Each behavior instance always controls the same graphic, but can display it in different channels depending on the graphic's current Z-depth. Here's the sequence: -- Each sprite in turn has its behaviors instantiated. They receive spriteNum and getPDL values from the Score in the usual way, and then broadcast a message via sendAllSprites, sending along a propList and a linearList as parameters. Each existing behavior instance then stores a reference to each of these list objects and adds its own data to these shared lists. (During initialization there are many extra messages and lists which are never used, but the flexibility of this approach means that sprites can start and end on different frames and still maintain current references to each other.) -- Before leaving each frame the 3D transforms are performed by each behavior instance. Each then removes its old zPos:obj reference from the shared sorted zList, and adds a new reference with its new zPos. Because the proplist is sorted this new behavior reference automatically goes into the correct position in the list. -- At prepareFrame, each behavior instance finds its position in the zList, and takes the sprite channel in the corresponding position of the list of available sprite channels. There's no need to hardwire a range of sprite channels, or even of using contiguous channels -- the behavior skeleton handles all of this automatically. The above suffices for non-interactive pieces. But if these sprites can react to user events, then there's a problem with the "this behavior controls that other sprite channel" approach: mouse events will appear to go to the wrong sprite. This is because the user associates their clicks with the thing they can see, while Director catches behaviors based upon their channels, or depth in the screen. It's possible to catch events in the current display channel and relay them to the behaviors in the sprite channel controlling the clicked graphic. Two things to watch for are infinite recursion, and preventing additional behaviors in the clicked channel from executing. You could add something like this to the above behavior skeleton: on mouseUp me, isPassedMessage if voidP(isPassedMessage) then -- it's a real mouseUp set whichChannel to getAt(ourSpriteList, getPos(ourZlist, me)) sendSprite(whichChannel, #mouseUp, TRUE) stopEvent -- prevents other behaviors on the clicked channel from firing end if end Here's a variant with info dumped to the Message Window: on mouseUp me, isPassedMessage if voidP(isPassedMessage) then put RETURN & "Caught by: " & spriteNum, the member of sprite spriteNum set whichChannel to getAt(ourSpriteList, getPos(ourZlist, me)) sendSprite(whichChannel, #mouseUp, TRUE) stopEvent else put "Relayed to: " & spriteNum, the member of sprite spriteNum end If using something like this with multiple behaviors on a sprite, then it's important to have this behavior at the top of the sprite's list of behaviors, so that it can "stopEvent" before other behaviors in the clicked channel evaluate the mouse event. Summary: Although it's not possible to sort a propList by an arbitrary property name, it's possible to create a second list for sorting and then cross-reference. A skeleton 3D behavior was shown, which handles behavior registration, sorting, display, and event-routing. The above should be doublechecked against your own experience and tests. Whew... hope I got that right, and that it's of interest.People have been doing great things with 3D displays in Director, and I'm personally looking forward to what you accomplish here in the future. jd
D. Plänitz