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-2025, Director Online. Article content copyright by respective authors.