QB64 Phoenix Edition
Joystick WIP - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Works in Progress (https://qb64phoenix.com/forum/forumdisplay.php?fid=9)
+---- Thread: Joystick WIP (/showthread.php?tid=3419)



Joystick WIP - SMcNeill - 01-26-2025

For testing purposes only, give this a try with your favorite joystick and see how this maps out/behaves.

Code: (Select All)
Type Axis_Type
Active As _Byte
Vert As Single
Hort As Single
Angle As Single
End Type
ReDim Shared As Axis_Type JoyStick(0)

Do
Cls
ReadJoyStick
For i = 1 To UBound(JoyStick)
If JoyStick(i).Active Then
Print Using "STICK # ACTIVE:"; i
Print JoyStick(i).Hort, JoyStick(i).Vert, JoyStick(i).Angle
End If
Next
_Limit 30
_Display
Loop

Sub ReadJoyStick
Static d, LA
If d = 0 Then d = _Devices
If d < 3 Then Exit Sub '3 is joystick. Without one, then there's no reason to waste effort doing anything else.
If LA = 0 Then LA = _LastAxis(3): ReDim JoyStick(1 To LA \ 2) As Axis_Type
If LA = 0 Then Exit Sub 'if there's no axis on your joystick, I don't know how to read it!
Dim axis(LA) As Single
Do
di = _DeviceInput
Select Case di
Case 3
For a = 1 To LA: axis(a) = _Axis(a): Next
For j = 1 To LA \ 2
If j = 1 Then
'left pad is axis 1 and 2
JoyStick(j).Hort = axis(j * 2 - 1): JoyStick(j).Vert = axis(j * 2)
Else
'axis 3 is the botton left/right buttons on the front of my joystick
'so the right pad is axis 4 and 5
'and the d-pad is axis 6 and 7
JoyStick(j).Hort = axis(j * 2 + 1): JoyStick(j).Vert = axis(j * 2)
'd-pad seems to be mapped backwards to the other axis??!!
If j = 3 Then Swap JoyStick(j).hort, JoyStick(j).vert
End If
Next
End Select
Loop Until di = 0
For j = 1 To LA \ 2
If Abs(JoyStick(j).Vert) <= .01 Then JoyStick(j).Vert = 0
If Abs(JoyStick(j).Hort) <= .01 Then JoyStick(j).Hort = 0
JoyStick(j).Angle = _Atan2(JoyStick(j).Hort, JoyStick(j).Vert)
JoyStick(j).Angle = (_R2D(JoyStick(j).Angle) + 270) Mod 360
If JoyStick(j).Vert = 0 And JoyStick(j).Hort = 0 Then JoyStick(j).Active = _FALSE Else JoyStick(j).Active = _TRUE
Next
End Sub


I've tested this on my Xbox-style joystick and... these mappings seem odd as BLEEP to me!

Left paddle is axis 1 and 2
Right paddle is axis 4 and 5
D-pad is axis 7 and 6

Axis 3 is the button left/right buttons on the front of the joystick
Note that the D-pad is REVERSED in order compared to the paddles.

Who the crap configures these things? Who thought this type of set up would be nice and normal and easy to configure for??

/sigh

Anywho... Test this out with your own joysticks and see if it responds as expected for you. So far, this just tests for the stick movement (it doesn't even try and tell you about those button-sticks!), but it *should* have x and y both mapped for all 3 axis.

Let me know if it works for you, or if it gives some odd readings, or whatnot. I have no idea how the heck this might work on various controllers. It's just... weird the mapping on this thing.



As for the angle, I've fixed it so it should map to the same coordinates as what we learned in school. 0 is to right, 90 is to the top, 180 is left and 270 is bottom. It should be the quickest way to tell if something is completely off with the left/right paddles.


RE: Joystick WIP - Pete - 01-26-2025

Sadly I retired my joystick many years ago. Oh shut up, Steve! Angry

Programming the joysticks and paddle controllers was pretty straight forward in Atari Basic. That's about the last time I remember making those types of game apps. Great to see it again though, in QB64PE.

I'm sure you'll get this one completed, just 'bear' with it!

Pete Big Grin


RE: Joystick WIP - SMcNeill - 01-26-2025

Code: (Select All)
Type Axis_Type
Active As _Byte
X As Integer
Y As Integer
Vert As Single
Hort As Single
Angle As Single
End Type
ReDim Shared As Axis_Type JoyStick(0)

Do
Cls
ReadJoyStick
For i = 1 To UBound(JoyStick)
If JoyStick(i).Active Then
Print Using "STICK # ACTIVE:"; i
Print "Hort:", JoyStick(i).Hort, "Vert:", JoyStick(i).Vert
Print "X:", JoyStick(i).X, "Y:", JoyStick(i).Y
Print "Angle:", JoyStick(i).Angle
End If
Next
_Limit 30
_Display
Loop

Sub ReadJoyStick
Static d, LA
If d = 0 Then d = _Devices
If d < 3 Then Exit Sub '3 is joystick. Without one, then there's no reason to waste effort doing anything else.
If LA = 0 Then LA = _LastAxis(3): ReDim JoyStick(1 To 3) As Axis_Type
If LA = 0 Then Exit Sub 'if there's no axis on your joystick, I don't know how to read it!
Dim axis(LA) As Single
Do
di = _DeviceInput
Select Case di
Case 3 'We have joystick input
For a = 1 To LA: axis(a) = Int(100 * _Axis(a)) / 100: Next 'read the input on each axis
JoyStick(1).Hort = axis(1): JoyStick(1).Vert = axis(2) 'left pad is axis 1 and 2
'axis 3 is the botton left/right buttons on the front of my joystick
JoyStick(2).Hort = axis(5): JoyStick(2).Vert = axis(4) 'right pad is axis 5 and 4
JoyStick(3).Hort = axis(6): JoyStick(3).Vert = axis(7) 'd-pad is axis 6 and 7
'right-pad seems to be mapped backwards to the other axis??!!
End Select
Loop Until di = 0
For j = 1 To 3
If Abs(JoyStick(j).Vert) <= .01 Then JoyStick(j).Vert = 0 'remove some natural drift from the keypad
If Abs(JoyStick(j).Hort) <= .01 Then JoyStick(j).Hort = 0 'my joystick seldom resets back to perfect 0
' the code below here gives me a simple X/Y value for left/right, up/down of _TRUE/_FALSE
'I personally find it easier for my 2-d style games to process than having to use frational results.
'Feel free to change the threshold as necessary for your own uses. 0.4 works fine for cardinal directions and diagionals for my use.
If Abs(JoyStick(j).Vert) > 0.4 Then JoyStick(j).Y = Sgn(JoyStick(j).Vert) Else JoyStick(j).Y = 0
If Abs(JoyStick(j).Hort) > 0.4 Then JoyStick(j).X = Sgn(JoyStick(j).Hort) Else JoyStick(j).X = 0
'the angle here is just like the one we learned in school with 0/360 to the right, 90 up, 180 left, and 270 down
'Tweak this as needed so it fits the coordinate system of your own stuff as desired.
JoyStick(j).Angle = _Atan2(JoyStick(j).Hort, JoyStick(j).Vert)
JoyStick(j).Angle = (_R2D(JoyStick(j).Angle) + 270) Mod 360
'And below here is what determines if a joystick was active or not
If JoyStick(j).Vert = 0 And JoyStick(j).Hort = 0 Then JoyStick(j).Active = _FALSE Else JoyStick(j).Active = _TRUE
Next
End Sub

Simplified my mapping logic. Added a lot more comments here as for what everything is doing. Simplified my input response for a simple True/False X/Y result.

I'm thinking all this needs now is buttons added, and then it'll be more or less usable.

Note that after going back and checking over my work, my comments were off. It's not the d-pad that's mapped backwards, it's the right-pad.

Left paddle is axis 1 and 2
Right paddle is axis 5 and 4
D-pad is axis 6 and 7


RE: Joystick WIP - SMcNeill - 01-26-2025

Code: (Select All)
Type Axis_Type
Active As _Byte
X As Integer
Y As Integer
Vert As Single
Hort As Single
Angle As Single
End Type
ReDim Shared As Axis_Type JoyStick(0)
ReDim Shared As Long Button(0)

Do
Cls
ReadJoyStick
For i = 1 To UBound(JoyStick)
If JoyStick(i).Active Then
Print Using "STICK # ACTIVE:"; i
Print "Hort:", JoyStick(i).Hort, "Vert:", JoyStick(i).Vert
Print "X:", JoyStick(i).X, "Y:", JoyStick(i).Y
Print "Angle:", JoyStick(i).Angle
End If
Next
Print Using "## Buttons Found"; UBound(Button)
For b = 1 To UBound(Button)
If Button(b) Then Print Using "Button ## down"; b
Next

_Limit 30
_Display
Loop

Sub ReadJoyStick
Static As Long d, LA, LB 'Last Axis, Last Button
If d = 0 Then d = _Devices
If d < 3 Then Exit Sub '3 is joystick. Without one, then there's no reason to waste effort doing anything else.
If LA = 0 Then LA = _LastAxis(3): ReDim JoyStick(1 To 3) As Axis_Type
If LA = 0 Then Exit Sub 'if there's no axis on your joystick, I don't know how to read it!
If LB = 0 Then LB = _LastButton(3): ReDim Button(1 To LB) As Long
If LB = 0 Then Exit Sub 'if there's no buttons on your joystick, then it's not a proper controller. Go buy one!

Dim axis(LA) As Single
Do
di = _DeviceInput
Select Case di
Case 3 'We have joystick input
For a = 1 To LA: axis(a) = Int(100 * _Axis(a)) / 100: Next 'read the input on each axis
JoyStick(1).Hort = axis(1): JoyStick(1).Vert = axis(2) 'left pad is axis 1 and 2
'axis 3 is the botton left/right buttons on the front of my joystick
JoyStick(2).Hort = axis(5): JoyStick(2).Vert = axis(4) 'right pad is axis 5 and 4
JoyStick(3).Hort = axis(6): JoyStick(3).Vert = axis(7) 'd-pad is axis 6 and 7
'right-pad seems to be mapped backwards to the other axis??!!
For i = 1 To LB
Button(i) = _Button(i)
Next
End Select
Loop Until di = 0
For j = 1 To 3
If Abs(JoyStick(j).Vert) <= .01 Then JoyStick(j).Vert = 0 'remove some natural drift from the keypad
If Abs(JoyStick(j).Hort) <= .01 Then JoyStick(j).Hort = 0 'my joystick seldom resets back to perfect 0
' the code below here gives me a simple X/Y value for left/right, up/down of _TRUE/_FALSE
'I personally find it easier for my 2-d style games to process than having to use frational results.
'Feel free to change the threshold as necessary for your own uses. 0.4 works fine for cardinal directions and diagionals for my use.
If Abs(JoyStick(j).Vert) > 0.4 Then JoyStick(j).Y = Sgn(JoyStick(j).Vert) Else JoyStick(j).Y = 0
If Abs(JoyStick(j).Hort) > 0.4 Then JoyStick(j).X = Sgn(JoyStick(j).Hort) Else JoyStick(j).X = 0
'the angle here is just like the one we learned in school with 0/360 to the right, 90 up, 180 left, and 270 down
'Tweak this as needed so it fits the coordinate system of your own stuff as desired.
JoyStick(j).Angle = _Atan2(JoyStick(j).Hort, JoyStick(j).Vert)
JoyStick(j).Angle = (_R2D(JoyStick(j).Angle) + 270) Mod 360
'And below here is what determines if a joystick was active or not
If JoyStick(j).Vert = 0 And JoyStick(j).Hort = 0 Then JoyStick(j).Active = _FALSE Else JoyStick(j).Active = _TRUE
Next
End Sub

With button support now.

This finds 10 buttons on my controller.

2 buttons are mapped as axis, so those aren't counted (yet). They'll need unique handling.

3 buttons aren't registering at all. Why?? I have no clue. _Devices just refuses to read them, just as it refuses to read any of the extra buttons on my mouse beyond left/right/middle.