Joystick position

From Rosetta Code
Revision as of 07:40, 7 September 2011 by rosettacode>Dkf (whitespace)
Task
Joystick position
You are encouraged to solve this task according to the task description, using any language you may know.

The task is to determine the joystick position and represent this on the display via a crosshair. For a centred joystick, the crosshair should appear in the centre of the screen. If the joystick is pushed left or right, then the cross hair should move left or right according to the extent that the joystick is pushed. If the joystick is pushed forward or pulled back, then the crosshair should move up or down according to the extent that that joystick is pushed or pulled. The edges of the display represent maximum extents for joystick movement. For example, a joystick pushed fully forward would raise the crosshair to the top centre of the screen. A joystick pulled backwards and to the right would move the crosshair to the bottom right of the screen (except for a small area reserved to show joystick status). Implementations can use a graphical display method to produce the crosshair, or alternatively represent the crosshair using a plus symbol on a terminal, and move the plus symbol position according to the joystick. The bottom part of the display can hide or show an alphanumeric sequence to represent the buttons pressed. For example, if pushbuttons 1,4 and 10 are depressed, we could display "1 4 A". The implemented code should continue to redraw the crosshair according to the joystick position and show the current pushbutton statuses until the task is terminated. Digital joysticks that produce no extent data, should have their position indicated as full extent movement of the crosshair.

For the purpose of this task, we assume that the joystick is calibrated and that the first joystick is being used. The task implementer could at their option provide a solution that includes a joystick selection facility, enabling the user to choose which joystick is to be used for this task.

GUISS

Graphical User Interface Support Script only makes use of installed applications. So for this task, we use the joystick calibration routine, which shows a joystick position indicator:

<lang guiss>Start,Control Panel, Game Controllers, List:installed controllers,Click:Joystick, Button:Properties,Button:Test</lang>

Liberty BASIC

<lang lb> 'disable text window

   nomainwin
   'set window size
   WindowWidth  = 308
   WindowHeight = 331
   'center window on screen
   UpperLeftX = int((DisplayWidth-WindowWidth)/2)
   UpperLeftY = int((DisplayHeight-WindowHeight)/2)
   'open graphics window
   open "Joystick Position" for graphics_nf_nsb as #m
   'trap window closing
   #m "trapclose [quit]"
   'put pen down
   #m "down"
   'get center of graphics window
   #m "home"
   #m "posxy CenterX CenterY"
   'draw sprite for crosshair
   #m "backcolor black; color black"
   #m "place 0 20;boxfilled 20 40"
   #m "line  0 10 20 10"
   #m "line 10  0 10 20"
   #m "place 10 10; circle 10"
   #m "backcolor white; color red"
   #m "line  0 30 20 30"
   #m "line 10 20 10 40"
   #m "place 10 30; circle 10"
   #m "flush"
   'get sprite image
   #m "getbmp plus 0 0 20 40"
   #m "cls"
   'create sprite from image
   #m "addsprite crosshair plus"
   #m "centersprite crosshair"
   #m "spritexy crosshair "; CenterX; " "; CenterY
   #m "drawsprites"
   'check joystick every 100 milliseconds
   timer 100, [CheckJoystick]
   wait

[CheckJoystick]

   readjoystick 1
   'calculate crosshair position
   PosX = int(CenterX*Joy1x/32767)
   PosY = int(CenterY*Joy1y/32767)
   'update crosshair position
   #m "spritexy crosshair "; PosX; " "; PosY
   #m "drawsprites"
   'display button information
   if Joy1button1 > 0 then #m "place 0 0;\\Button 1 pressed"
   if Joy1button2 > 0 then #m "place 0 0;\\\Button 2 pressed"
   wait

[quit]

   timer 0
   close #m
   unloadbmp "plus"
   end</lang>

Locomotive Basic

<lang locobasic>10 MODE 1:BORDER 14:x=320:y=200:d=1 20 a=JOY(0) ' read state of first joystick 30 IF d THEN q$="*" ELSE q$=" " 40 IF a THEN MOVE x-8,y+8:TAG:PRINT q$;:TAGOFF 50 IF (a AND 1) AND y<380 THEN y=y+10 60 IF (a AND 2) AND y>20 THEN y=y-10 70 IF (a AND 4) AND x>20 THEN x=x-10 80 IF (a AND 8) AND x<620 THEN x=x+10 90 IF a AND 16 THEN LOCATE 1,1:PRINT "Fire1 pressed":d=1 100 IF a AND 32 THEN LOCATE 1,2:PRINT "Fire2 pressed":d=0 110 IF a<16 THEN LOCATE 1,1:PRINT " ":PRINT " " 120 MOVE x-8,y+8:TAG:PRINT "X";:TAGOFF 130 GOTO 20</lang>

Output (this version supports drawing with the cursor):

Mathematica

<lang Mathematica>Slider2D[Dynamic[ControllerState[{"X", "Y"}]], ImageSize -> {500, 500}]</lang>

PicoLisp

This is for the 64-bit version.

Note: The code is not yet tested with a real joystick (I don't have one), it was just simulated with dummy functions. Can somebody having a joystick please test it, and remove this message? <lang PicoLisp>(load "@lib/openGl.l")

(setq *JoyX 0.0 *JoyY 0.0)

(glutInit) (glutInitDisplayMode (| GLUT_RGBA GLUT_DOUBLE GLUT_ALPHA GLUT_DEPTH)) (glutInitWindowSize 400 400) (glutCreateWindow "Joystick")

(glClearColor 0.3 0.3 0.5 0)

(displayPrg

  (glClear GL_COLOR_BUFFER_BIT)
  (glBegin GL_LINES)
  (glVertex2f *JoyX (- *JoyY 0.1))  # Draw crosshair
  (glVertex2f *JoyX (+ *JoyY 0.1))
  (glVertex2f (- *JoyX 0.1) *JoyY)
  (glVertex2f (+ *JoyX 0.1) *JoyY)
  (glEnd)
  (glFlush)
  (glutSwapBuffers) )
  1. Track joystick position

(native `*GlutLib "glutJoystickFunc" NIL

  (lisp 'joystickFunc
     '((Btn X Y Z)
        (msg                          # Display buttons
           (make
              (for (B 1 (n0 Btn) (inc B))
                 (and (bit? 1 Btn) (link B))
                 (setq Btn (>> 1 Btn)) ) ) )
        (setq                         # Move crosshair
           *JoyX (*/ X 1.0 1000)
           *JoyY (*/ Y 1.0 1000) )
        (glutPostRedisplay) ) )
  100 )
  1. Exit upon mouse click

(mouseFunc '((Btn State X Y) (bye))) (glutMainLoop)</lang>

PureBasic

This is limited to only digital joysticks. <lang PureBasic>If InitJoystick() = 0

 MessageRequester("Error!", "Need to connect a joystick", #PB_MessageRequester_Ok)
 End

EndIf

some constants for Window positioning
  1. WindowW = 100: #WindowH = 100
  2. CrossW = 10
  3. p1 = (#WindowW - #CrossW) / 2
  4. p2 = (#WindowW / 2 - #CrossW)

If OpenWindow(0, 0, 0, #WindowW * 2 + 10, #WindowH, "Joystick Position", #PB_Window_SystemMenu)

 CreateImage(0, #WindowW, #WindowW)
 ImageGadget(0, 0, 0, 0, 0, ImageID(0))
 TextGadget(2, #WindowW + 5, 10, #WindowW, 20, "Buttons Pressed:")
 CreateImage(1, #WindowW, 40)
 ImageGadget(1,  #WindowW + 5, 30, 0, 0, ImageID(1))
 
 AddKeyboardShortcut(0, #PB_Shortcut_Escape, 0)
 Define event, x_movement, y_movement
 Repeat 
   Repeat
     event = WindowEvent()
     Select event
       Case #PB_Event_Menu
         If EventMenu() = 0
           End
         EndIf
       Case #PB_Event_CloseWindow
         End
     EndSelect
   Until event = 0
   
   Define pressed.s, buttonNum, buttonX, buttonY, buttonText.s, buttonColor
   pressed.s = ""
   If ExamineJoystick(0)
     x_movement = JoystickAxisX(0)
     y_movement = JoystickAxisY(0)
     
     StartDrawing(ImageOutput(1))
       DrawingMode(#PB_2DDrawing_Transparent)
       Box(0, 0, #WindowW, 50, RGB($D4, $D0, $C8)) ;a Gray
       ; check to see if any of the buttons have been pressed
       For buttonNum = 1 To 10
         buttonX = ((buttonNum - 1) * 20 + 10) % #WindowW
         buttonY = ((buttonNum - 1) / 5) * 20 + 10
         If JoystickButton(0, buttonNum)
           buttonColor = RGB($FF, 0, 0) ;Red
         Else
           buttonColor = RGB($80, $80, $80) ;Gray
         EndIf 
         Circle(buttonX, buttonY, 9, buttonColor)
         buttonText = Str(buttonNum)
         DrawText(buttonX - TextWidth(buttonText) / 2, buttonY - TextHeight(buttonText) / 2, buttonText, RGB($FF, $FF, $FF)) ;White
       Next
     StopDrawing()
     
     SetGadgetState(1, ImageID(1))
   EndIf
   
   
   StartDrawing(ImageOutput(0))
     Box(0,0, #WindowW, #WindowW, RGB($FF, $FF, $FF)) ;White
     Line(#p1 + x_movement * #p2, #WindowW / 2 + y_movement * #p2, #CrossW, 1, RGB($FF, 0, 0)) ;Red
     Line(#WindowW / 2 + x_movement * #p2, #p1 + y_movement * #p2, 1, #CrossW, RGB($FF, 0, 0)) ;Red
   StopDrawing()
   
   SetGadgetState(0, ImageID(0))
   
   Delay(10)
 Until event = #PB_Event_CloseWindow

EndIf</lang>