Not logged inOpenClonk Forum
Up Topic Development / Developer's Corner / Gamepad support
- - By Luchs [de] Date 2016-02-15 18:09 Edited 2016-02-21 17:16
I'm currently working on improving OC's gamepad support. The source code is available on github. (diff)

What's working already?



- I changed the gamepad input on all platforms to use the SDL gamecontroller API. This API abstracts the usual numbered buttons to provide a single controller layout which looks like an Xbox controller. This allows us to create more advanced mappings which can use all of the available buttons, sticks and triggers on the controller. This also makes XInput controllers such as the Xbox and Steam controllers available on Windows. (I didn't try building the code on Windows yet.)

- I made analog input from the gamepad sticks and triggers available to the script. There already was a strength parameter, but it was only updated once when moving the stick. With my changes, the PlayerControl() function continuously receives stick movement events. Additionally, the sticks and triggers still send regular "key down" and "key up" events for cases where analog input isn't needed (for example menus).

- Make GetPlayerControlState() query the current position of analog sticks and not the emulated button state. (optional via third parameter)

- Improve main menu controls with the gamepad. Previously, these controls used a simple mapping heuristic with odd/even buttons etc. This isn't necessary anymore because we know exactly what the controller looks like. The main menu can now be controlled with the left stick or the dpad and the A/B buttons.

- Implement controller rumbling / force feedback (the simple rumbling provided by SDL is probably enough for now): StartRumble(int plr, int strength, int length) and StopRumble(int plr)

- Documentation. The strength parameter to PlayerControl() now receives the full range 0-32767/32768 exposed by SDL. The release flag has been replaced with a status parameter with the possible values CONS_Down, CONS_Up, CONS_Moved. Third parameter of GetPlayerControlState() makes the function query the current strength of an analog stick or trigger. StartRumble/StopRumble.

- Automatic controller selection and hot plugging. The available controllers are automatically distributed among all players with gamepad controls. It is possible to start a game without a gamepad, controls work as soon as a controller is plugged in. When removing a controller while playing, the game is paused and controls continue to work after plugging the controller back in.

- Controlling multiple players with gamepads. There are a few issues with split screen play (broken HUD, music), but the gamepad controls work fine.

Todo list



- Implement analog movement and aiming in script. Create a good controller mapping which is competitive with keyboard/mouse controls. (Would be cool if someone who's familiar with the existing gamepad controls could help here.)

- Improve control device selection. The current method where the device number of the gamepad is baked into the control scheme doesn't make a lot of sense. There probably should be a separate player selection screen when starting a game both locally and over the network. On this screen, each player would select their player file with the controller or keyboard/mouse they want to play with. (I will probably need some help here as well.)

- Re-enable split-screen playing. Currently, it isn't possible to select more than one player at once.

- Code review: I'm new to engine modifications so I don't really know whether my changes actually make sense :)

- Improve main menu UX with keyboard and controller. For example, when leaving a scenario folder, the selection bar should already be on the folder we just left. There are also some things which are possible with the keyboard, but lack proper gamepad bindings (e.g. crew selection).
Parent - - By Newton [de] Date 2016-02-16 00:56
Cool stuff! A few comments:

>There already was a strength parameter, but it was only updated once when moving the stick. With my changes, the PlayerControl() function continuously receives stick movement events.


Why? IIRC if the mouse does also not spawn a new mouse event every frame even if it is not moved, right?

> This isn't necessary anymore because we know exactly what the controller looks like.


Does this mean the game will only work with XBOX like controllers? What about PS-like controllers?
Parent - - By Luchs [de] Date 2016-02-16 09:25

>Why? IIRC if the mouse does also not spawn a new mouse event every frame even if it is not moved, right?


I'm not sure what you're trying to say there, but I can explain a bit more: Previously, the analog sticks were translated to button presses. Think of a mouse that would only send a single event "left" if you're moving it to the left and "up" when moving it back. That's not enough to do get the precise location of the mouse cursor, or the position of the analog stick. (It may be enough for mouse input as the cursor location usually only matters when clicking, but that's an optimization we cannot do for analog sticks.)

Now, every time the controller sends an updated stick position, the new position is sent to the script. If you don't move any sticks or triggers, no calls are made. However, the sensors are so sensitive that the position will even change slightly if you're just holding the controller in the hand without touching any of the sticks. If it turns out that we have too may events, we could introduce a "minimum movement" threshold.

>What about PS-like controllers?


This is mainly about the presence of buttons and sticks, not about the exact layout. For our purposes, a PS controller is the same thing. The only disadvantage you'll have with a PS controller is that the X/Y/A/B button labeling does not match. That's still better than the previous button numbering which matched neither the PS controller nor the Xbox controller.
Parent - By Newton [de] Date 2016-02-16 10:53
Ah, okay. I did not understand it correctly.
Parent - - By Mupf [de] Date 2016-02-16 11:46
Wouldn't it be possible to let the player select between the 3 of the most popular controller labelings?
XBox, PS, Steam?
Parent - - By Luchs [de] Date 2016-02-16 11:56
Steam and Xbox are the same. PS is tricky anyways because the shapes aren't included in our font.
Parent - - By Mupf [de] Date 2016-02-16 12:51
Well, I guess PS controllers are only used by people who own a PlayStation anyway, so that shouldn't be a bummer for too many people.
I didn't know that XBox and Steam controller buttons are labeled the same.
Parent - - By Newton [de] Date 2016-02-16 15:11
Ah, I was going to protest because I have these from Logitech

But I realized that this layout which I thought of as "PS alike" is as much PS alike as Xbox or Steam controllers.
Parent - - By Zapper [de] Date 2016-02-16 16:27
I have this generic one:


But I guess as long as I have two analog sticks, one arrow pad and four buttons (and possibly additional four on the rear), I should be fine?
Parent - - By Luchs [de] Date 2016-02-16 18:08
Yup. SDL uses a database to map button numbers to their equivalents on the Xbox controller. For example, on your controller, 1 is mapped to Y, 2 to B, and so on. If your controller isn't included in the database, you'll have to create a mapping yourself. The easiest way to do this is by launching Steam's Big Picture mode which will ask you to configure your controller if it isn't supported by SDL. The mapping it creates is then automatically passed to games started with Steam with an environment variable.

It would be interesting to hear whether this actually works - I only have XInput controllers which don't need any mapping (because they only support the Xbox controller layout).
Parent - By Zapper [de] Date 2016-02-16 18:29
Ah, that's actually pretty neat.

I have already used the Big Picture mode with that gamepad and I can't remember having to explicitely configure it beforehand
Parent - - By Newton [de] Date 2016-02-16 19:43
Are you interested in getting a few controllers sent to you via post?
Parent - By Luchs [us] Date 2016-02-16 20:46
Thanks, but I hope SDL has controller differences sorted out and this won't be necessary. I'd wait for feedback once we get something playable.
Parent - By Mupf [de] Date 2016-02-16 19:05
These Logitech ones are probably the most popular PC controllers after XBox, didn't mention them because they have the same button names.
Parent - - By Günther [de] Date 2016-02-16 13:20
The font can be changed, though. What are the unicode values we'd need?
Reply
Parent - - By Isilkor Date 2016-02-17 04:20 Edited 2016-02-17 04:25
Probably something in the PUA. Alternatively if we want to use standard geometric shapes without specially marking them as "gamepad buttons" in the font, U+25A1 WHITE SQUARE "□", U+25B3 WHITE UP-POINTING TRIANGLE "△", U+25CB WHITE CIRCLE "○", U+274C CROSS MARK "❌"?
Reply
Parent - - By Günther [de] Date 2016-02-19 10:51
The other buttons aren't marked as "gamepad buttons" or "keyboard buttons" either, so standard geometric shapes are totally the way to go.
Reply
Parent - - By Isilkor Date 2016-02-19 14:20
Yeah but I feel we should mark them differently so we can render them in the proper color.
Reply
Parent - - By Luchs [de] Date 2016-02-19 16:04
Maybe we should just use a set of bitmap icons instead. This one seems nice.
Parent - - By Sven2 [us] Date 2016-02-19 17:21
You could add them to the handler that resolves the {{Ico:Name}} specifications allowed in texts. But it won't scale as nicely for different font sizes.
Parent - - By Maikel Date 2016-02-19 17:56
Since when does Icon:Name work? I still wanted to use some icons for the tutorial messages.
Parent - By Luchs [de] Date 2016-02-19 19:43
It's actually {{@Ico:name}}, where name ∈ {Locked, League, GameRunning, Lobby, RuntimeJoin}.
Parent - By Sven2 [us] Date 2016-02-19 21:35
That's only for internal icons that need to be available before objects have been loaded. Normal scripts can just do {{ID}}.
Parent - By Luchs [de] Date 2016-02-19 19:38 Edited 2016-02-19 20:02
Thanks for the hint, seems to work nicely in-game. Now I just need to figure out how to get these to work in the control list...

Edit: Wasn't hard to do and looks good.
Parent - By Luchs [de] Date 2016-02-19 15:56
The arrows U+2190 to U+2193 would also be nice. "Left Stick Left/Right/Up/Down" looks a bit confusing compared to "Left Stick ←".
Parent - - By Sven2 [us] Date 2016-02-16 13:30
You may also send the current position in C4PlayerControl::PrepareInput. That way it will only be sent once per control frame.
Parent - By Luchs [de] Date 2016-02-16 17:07
Thanks for the hint. I completely missed that analog input was mostly already in place, just not implemented in the old SDL joystick code. (I started by removing all Windows-specific code.)

I think my changes are still beneficial as they allow script authors to treat gamepad sticks and triggers as buttons if that's all they need, while still having access to the raw controller state.
Parent - By Luchs [de] Date 2016-02-17 21:51

>Implement controller rumbling / force feedback


SDL also supports haptic mice, but I have never seen one. Does anyone have one and wants this to work? ;)
- - By Luchs [de] Date 2016-02-21 18:59
I opened a pull request for this: https://github.com/openclonk/openclonk/pull/17

I think this is done as far as the most important engine changes go. The remaining todos there (improved main menu controls, gamepad selection when multiple players use gamepad controls) would be nice to have, but aren't very important (players can use a mouse for things not accessible with the controllers, and can plug out controllers they don't want to use).

To make all of this actually useful, a lot of work on the script is necessary. Merging the engine changes will make snapshots available, making the script part easier.
Parent - - By Armin [de] Date 2016-02-21 21:37
For some reason, when I compile it, the game tells me there is no gamepad for my player and I should plug it in. (Linux, Controller)
Parent - - By Luchs [de] Date 2016-02-21 22:45
Do you have SDL2 installed and did cmake report that it found SDL2? It's possible to compile the engine without SDL, but then gamepads won't work.

It should definitely work on Linux with this controller, as that's exactly my test setup.
Parent - - By Armin [de] Date 2016-02-22 00:21

>Do you have SDL2 installed and did cmake report that it found SDL2?


Yes. I hope its normal that cmake colors all lines red and when pressing Configure a second time, all lines become white. I wait for snapshots, it is likely I'm doing something wrong anyway.
Parent - By Isilkor Date 2016-02-22 01:18

> I hope its normal that cmake colors all lines red and when pressing Configure a second time, all lines become white.


The red background means "this setting is new" (so you can consider whether you want to change it). It's not an error.
Reply
Parent - - By Luchs [de] Date 2016-02-22 15:37
Does the gamepad work correctly in other applications? I sometimes have to reconnect the controller after using suspend.

You could try to compile this tool, it uses the same SDL2 API to talk to the controller. It should print something like this (the GUID will obviously be different):

% sdl2-jstest -l
Found 1 joystick(s)

Joystick Name:     'Microsoft X-Box 360 pad'
Joystick GUID:     030000005e0400008e02000014010000
Joystick Number:    0
Number of Axes:     6
Number of Buttons: 11
Number of Hats:     1
Number of Balls:    0
GameController:
  Name:    'XInput Controller'
  Mapping: '(null)'


Additionally, sdl2-jstest -g 0 should work and sdl2-jstest -r 0 should make your controller rumble (hint: pick it up before running).
Parent - - By Armin [de] Date 2016-02-22 19:18
[19:03 root .../sdl-jstest/build (master)]# ./sdl2-jstest -l
Found 1 joystick(s)

Joystick Name:     'Microsoft X-Box 360 pad'
Joystick GUID:     030000005e0400008e02000014010000
Joystick Number:    0
Number of Axes:     6
Number of Buttons: 11
Number of Hats:     1
Number of Balls:    0
GameController:
  Name:    'X360 Controller'
  Mapping: '030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,'

The other two commands worked fine, too. Nice rumble.

>Does the gamepad work correctly in other applications?


Yes it works everywhere I use it (Steam games & dolphin emulator). I also already tried a bunch of stuff like installing all packages that contain "sdl", using different USB slots and I've redone cmake&compile after installing that libcurse.
Parent - By Luchs [de] Date 2016-02-22 23:03
This is interesting - SDL seems to use the standard joystick interface to talk to the controller instead of using XInput, so a mapping is needed.
Parent - - By Armin [de] Date 2016-02-22 22:08 Edited 2016-02-22 22:32
Working now! I noted that every time I start a scenario, I can't do anything and the log tells me that there is no controller. But when I end the scenario and start the same or another scenario, it works. When I close and restart OpenClonk after that, I have to do this again - the first try does never work here. I think it's been like that since you told me that OC can compile without SDL lol. I always closed OC when I noted that it does not work on the first try because I thought the success chance would be higher when restarting Clonk after changing something like switching usb slot e.g.
Parent - By Luchs [de] Date 2016-02-22 23:10
This is odd, as there really isn't anything special about starting or ending a game. The controller should only be opened once on startup. You could try plugging the controller out and back in when it isn't recognized.
Parent - - By Luchs [de] Date 2016-02-23 17:14
I just added some logging when controllers are added/removed and assigned to players. This may help figuring out what happens on your machine. It should look something like this (I removed and reconnected the controller after starting the game):


[17:01:24] OpenClonk
[17:01:24] Version: 8.0-alpha unix linux-x86_64 (876c31fc2e6f)
[...]
[17:01:24] Gamepad #0 connected: Microsoft X-Box 360 pad
[...]
[17:01:30] Game started.
[17:01:30] Player join: Test
[17:01:30] Test: Using gamepad #0.
[17:01:41] Gamepad #0 disconnected.
[17:01:41] Test: No gamepad available.
[17:01:45] Gamepad #1 connected: Microsoft X-Box 360 pad
[17:01:48] Test: Using gamepad #1.
Parent - - By Armin [de] Date 2016-02-23 18:59
Here are the logs:
#1 Start a scen, restart a scen.
#2 Remove and reconnect controller, then do the same as in #1. I repeated this because "Gamepad #1 connected" came twice -> Same result.
Parent - - By Luchs [de] Date 2016-02-23 19:20 Edited 2016-02-23 20:21
Ah, I get it now. The issue is that the GTK build is only polling gamepad events after the game started. I was mainly testing with the "full" SDL platform and somehow didn't notice this when testing the GTK variant. Thanks for your help!

(It should also work if you unpause the game after starting. It pauses the game automatically to give players a chance to plug their controller in. There's currently no way to unpause the game with the controller, but that will hopefully be possible in the future.)

Edit: I pushed a fix now. This also makes gamepad controls available in the main menu, provided that GamepadGuiControl is set in the configuration.
Parent - By Armin [de] Date 2016-02-23 20:45
Fix works :)
Parent - - By Luchs [de] Date 2016-03-10 19:57
Is there anything else I can do to help getting this merged? This would allow more people (who can't compile their own engine) to test it out with their controllers. Additionally, I don't want to spend time on the script side of the gamepad controls while risking that my proposed new script interfaces may be refused in a few weeks.
Parent - - By Sven2 [us] Date 2016-03-10 20:40
Are the script changes compatible for non-gamepad controls? I.e. can we just merge it and the rest of the game still works?
Parent - - By Luchs [de] Date 2016-03-10 20:53
Yes. The main difference for non-gamepad controls is that the bool release parameter is now an int with three possible values. However, this isn't used yet (only "key down" and "key up" events are passed through). This way, even the gamepad controlls work just (as badly) as before.
Parent - - By Sven2 [us] Date 2016-03-10 21:23
Then the best next step is probably to merge it to master?
Parent - By Luchs [de] Date 2016-03-10 21:24
Yes, that's the plan.
Parent - By Zapper [de] Date 2016-03-10 22:53
Let's just give Luchs push access already
Up Topic Development / Developer's Corner / Gamepad support

Powered by mwForum 2.29.7 © 1999-2015 Markus Wichitill