Drag and Drop puzzles
September 14, 1998
by Pat McClellan
Dear Multimedia Handyman,
I'm a Director beginner and I need to create a puzzle so that each piece is moveable, but then locks into place when it is dropped in the right spot. I have checked the Moveable box on the score, but I don't know how to test the location and turn that off. Help please...
Singh
Dear Singh,
This seems like a common task that many people would want to do, so that makes it perfect for creating a behavior. That way, you can re-use it on future projects. This is also a fairly simple task, so it makes for a good "first behavior" for you to tackle.
Here's what we need to accomplish. In the beginSprite handler, we'll want to set the moveable property of the sprite to true. This is the same as clicking on the box in the score window, but we'll take care of it with Lingo instead. Next task, check immediately to see if the piece is in place (by chance). We can use create a testLoc handler for that. In the testLoc handler, we need to compare the current location of the sprite to our target location. That means that we'll want to allow the author to specify a target locH and a target locV during development. I also recommend that we allow for some "slop" or variance of position. If the user gets within a few pixels of the correct location, then we should lock the piece into place and give them credit as correct.
Now, when the user clicks on the mouse and drags the piece, we really don't do anything. We spring into action when the user releases the mouse. So in the mouseUp handler, we'll simply call the testLoc handler again.
Once the piece is in place, we will want to turn the moveable property off. I also like to play a little click sound for a little style. The last task is a little more complicated -- checking to see if they've won. After a piece locks into place, we'll set a status property to #inPlace, then go check the status of the other pieces. If any of the pieces report that that are #notInPlace, then we know the puzzle is not finished so we don't have to do anything else. However, if all of the other sprites report that they are #inPlace, then we will execute a puzzleFinished handler.
Here's the behavior:
--PuzzleDrop Behavior --copyright © 1998 ZZP Online, LLC --This behavior allows a sprite to be moved around -- the stage. On mouseUp, the sprite will compare -- its loc to a targetLoc. If it is within the -- acceptable target range, then the sprite locks -- into place. property pTargetH property pTargetV property pVariance property pTargetLoc -- point(pTargetH, pTargetV) property pMySprite property pStatus -- #inPlace or #notInPlace on getPropertyDescriptionList me set pdlist to [:] addprop pdlist, #pTargetH, [#comment:"Target ¬ locH", #format:#integer, #default:0] addprop pdlist, #pTargetV, [#comment:"Target ¬ locV", #format:#integer, #default:0] addprop pdlist, #pVariance, [#comment:"Acceptable¬ Variance", #format:#integer, #default:0] return pdlist end getPropertyDescriptionList on beginSprite me set pMySprite = the spriteNum of me set the moveableSprite of sprite pMySprite to TRUE set pTargetLoc = point(pTargetH, pTargetV) set pStatus = #notInPlace testLoc me end on mouseUp me testLoc me end on testLoc me set testH = the locH of sprite pMySprite set testV = the locV of sprite pMySprite if abs(pTargetH - testH) < pVariance then if abs(pTargetV - testV) < pVariance then set the loc of sprite pMySprite = pTargetLoc set the moveableSprite of sprite pMySprite ¬ to FALSE puppetSound 3, "click" set pStatus = #inPlace updateStage checkWin me end if end if end on checkWin me set statusList = [] sendAllSprites (#reportStatus, pMySprite, statusList) if getOne(statusList, #notInPlace) then nothing else puzzleFinished me end if end on reportStatus me, whichSprite, statusList if whichSprite <> pMySprite then add statusList, pStatus end if end on puzzleFinished me alert "You did it!" end
The trickiest part of this behavior is the way that I'm communicating between sprites. In the checkWin handler, I initiate the intersprite communcation by issuing a sendAllSprites command. This tells all the sprites to report their status by adding their status property to the statusList. This list is copied and altered by each sprite. Since it's a copy of the list, all changes are reflected on the orginal statusList. Therefore, we don't even have to pass the list back to the initiating sprite. Then, the checkWin handler scans the resulting list for determining whether all the pieces are in place.
This behavior makes it a simple task to assemble a drag and drop-in-place exercise. The only tedious part is writing down all the target locs for your sprites. If you do a lot of these or have a lot of pieces, you might want to create a quick utility handler. For example, put all of the sprites in the correct location. For this example, I'll assume we have 50 pieces, in sprite channels 5-54. Create the following movie script:
on listLocs firstSprite, lastSprite set spriteList = [:] repeat with i = firstSprite to lastSprite addProp spriteList, i, the loc of sprite i end repeat put spriteList end
Now, with the score on the frame where all of the sprites are in place, open the Message window and enter:
listLocs 7,10
The listLocs handler will return a property list, which you can refer to when entering the target locH and locV for your sprites.
-- [5: point(232, 148), 6: point(72, 170), 7: ¬ point(168, 183), 8: point(13, 218)... etc.]
Good luck with your program.
For those of you who like jigsaw puzzles -- or just damn impressive Lingo -- check out Jim Collins' puzzles at http://venuemedia.com/mediaband/collins/jigsaw_puzzles/.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.