Articles Archive
Articles Search
Director Wiki
 

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.

Patrick McClellan is Director Online's co-founder. Pat is Vice President, Managing Director for Jack Morton Worldwide, a global experiential marketing company. He is responsible for the San Francisco office, which helps major technology clients to develop marketing communications programs to reach enterprise and consumer audiences.

Copyright 1997-2024, Director Online. Article content copyright by respective authors.