Have Joystick. Will travel
September 21, 1998
by Pat McClellan
Dear Multimedia Handyman,
In Director, I have a picture of a joystick and I want the user to be able to click and drage the stick to make it "bend" to the left and to the right by swapping the image of the joystick. It should work pretty much like the real thing.
Marcus Lindberg
Dear Marcus,
If you want to do it with cast swapping and you're only going left-right, all you'll need is a script that watches the mouseH while the mouse is still down. For this example, the range of motion is 200 pixels and I have created 19 cast members (using the Auto Distort feature in the paint window.) So, as I move the mouse left & right, the cast members need to be swapped for every 10 and a half pixels of motion.
Something like this:
-- This behavior swaps cast -- members based on the mouseH property pMySprite property pStartMem property pRange property pHowManyMems property pCastLib property pFlag property pStartH property pHInterval on getPropertyDescriptionList me set pdlist to [:] addprop pdlist, #pRange, [#comment:"How many ¬ pixels in range?", #format:#integer, ¬ #default:200] addprop pdlist, #pHowManyMems, [#comment:"How ¬ many castMems in range?", #format:#integer, ¬ #default:19] return pdlist end getPropertyDescriptionList on beginSprite me set pMySprite = the spriteNum of me set pCastLib = the castLibNum of sprite pMySprite set pStartMem = the memberNum of sprite pMySprite set pFlag = #static set pHInterval = pRange/pHowManyMems end on mouseDown me set pFlag = #moving set pStartH = the mouseH end on mouseUp me set pFlag = #static end on mouseUpOutside set pFlag = #static end mouseUpOutside on exitFrame me if pFlag = #moving then set deltaH = the mouseH - pStartH if abs(deltaH) « (pRange/2) then set whichMem = pStartMem + deltaH/pHInterval set the member of sprite pMySprite = member ¬ whichMem of castLib pCastLib sendAllSprites(#joystickUpdate, deltaH) end if else set the member of sprite pMySprite = member ¬ pStartMem of castLib pCastLib end if end
Whatever the joystick is controlling will need a behavior attached which has a "joystickUpdate" handler. The exitFrame handler above sends a message to all sprites to do whatever they need to do in response to the change in horizontal position of the joystick.
As you play with this movie, you'll discover that it's difficult to maintain the contact between the mouse and the joystick. The problem is that the graphic really doesn't "know" where it is. Plus, the horizontal motion is linear, while the graphic rotation is not.
Here's a different approach that I think works a bit better. In this case, we're adding up/down to left/right -- like a real joystick uses. Instead of swapping cast members, I'm going to create the joystick with 2 cast members and 2 behaviors. The first cast member is the "knob" of the joystick. It will simply be a moveable cast member, constrained to a sprite below it (which could be invisible if you want.) The other sprite will be a simple line, drawn with the Director tool palette. It will adjust its width, height and position to "tag along" with the motion of the knob.
-- Joystick Knob Behavior -- Apply to the "knob" sprite of a joystick. property pConstraintSprite property pMySprite property pCenter property pSpring property pFlag property pStartV, pStartH on getPropertyDescriptionList me set pdlist to [:] addprop pdlist, #pConstraintSprite, [#comment:¬ "Constrain to which sprite?", #format:¬ #integer, #default:1] addprop pdlist, #pSpring, [#comment:"Joystick ¬ springs back?", #format:#boolean, #default:1] return pdlist end getPropertyDescriptionList on beginSprite me set pMySprite = the spriteNum of me set the constraint of sprite pMySprite ¬ to pConstraintSprite set the moveableSprite of sprite pMySprite to True set pCenter = the loc of sprite pMySprite if pSpring = FALSE then set pStartH = the locH of pCenter set pStartV = the locV of pCenter end if end on mouseDown me set pFlag = #moving if pSpring = TRUE then set pStartV = the mouseV set pStartH = the mouseH end if end on exitFrame me if pFlag = #moving then set deltaH = the locH of sprite pMySprite¬ - pStartH set deltaV = the locV of sprite pMySprite ¬ - pStartV sendAllSprites(#JoystickUpdate, deltaH, deltaV,¬ pCenter, pSpring) end if end on mouseUp me if pSpring then set the loc of sprite pMySprite to pCenter sendAllSprites(#JoystickCenter) end if set pFlag = #static end on mouseUpOutside me if pSpring then set the loc of sprite pMySprite to pCenter sendAllSprites(#JoystickCenter) end if set pFlag = #static end on toggleSpring me if pSpring = TRUE then set pSpring = FALSE else set pSpring = TRUE set the loc of sprite pMySprite to pCenter sendAllSprites(#JoystickCenter) end if end
For the knob in this example, I used a Flash Asset. This allows it to be nicely antialiased. The fact that it is a Flash Asset is irrelevant to the behavior. I also added a "spring" option, allowing you to decide whether the joystick should spring back to the center when released.
Now, to create the "stick" portion, you'll need to create 2 line cast members: one with a positive slope (up to the right) and one with a negative slope (down to the right). This behavior is tricky in that we have to switch between these members based on the position of the knob. In the top right and bottom left quadrants, the slope is positive, while it is negative in the other quadrants.
-- Joystick stick -- Apply to the "stick" portion of the joystick property pMySprite property pPosSlope property pNegSlope property pMyWidth, pMyHeight on getPropertyDescriptionList me if the currentspritenum = 0 then set memdefault = 0 else set memref = the member of sprite ¬ the currentspritenum set castlibnum = the castlibnum of memref set myMem = member(the memberNum of member ¬ memref) of castLib castLibNum set nextMem = member(the memberNum of member ¬ memref + 1) of castLib castLibNum end if set pdlist to [:] addprop pdlist, #pPosSlope, [#comment:"Positive ¬ Sloping member:", #format:#member, ¬ #default: myMem] addprop pdlist, #pNegSlope, [#comment:"Negative ¬ Sloping member:", #format:#member, ¬ #default:nextMem] return pdlist end getPropertyDescriptionList on beginSprite me set pMySprite = the spriteNum of me end on joystickCenter me set the height of sprite pMySprite = 0 set the width of sprite pMySprite = 0 end on joystickUpdate me,deltaH,deltaV,center,springStatus set the width of sprite pMySprite = ¬ max(4,abs(deltaH)) set the height of sprite pMySprite = ¬ max(4,abs(deltaV)) if deltaH > 1 then -- right side set the locH of sprite pMySprite = the ¬ locH of center if deltaV > 1 then -- bottom set the member of sprite pMySprite = pNegSlope set the locV of sprite pMySprite= the ¬ locV of center else -- top set the member of sprite pMySprite = pPosSlope set the locV of sprite pMySprite = the locV ¬ of center + deltaV end if else -- left side set the locH of sprite pMySprite = (the locH of ¬ center) + deltaH if deltaV > 1 then -- bottom set the member of sprite pMySprite = pPosSlope set the locV of sprite pMySprite = the locV ¬ of center else -- top set the member of sprite pMySprite = pNegSlope set the locV of sprite pMySprite = the locV ¬ of center + deltaV end if end if end
Like the first approach, the "knob" behavior sends out a message to all sprites to update themselves, along with the necessary deltaH and deltaV information.
Good luck with your project.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.