Porting to AirConsole: Making 10 fps input work
In today’s blog I will describe the techniques that we used to make Basher Beatdown, a fast paced game, work with 10 fps. A lot of info will be about the way we handle data on the controller itself but in the end we will also go over some gameplay changes that were made.
1. Optimizing data send
Sending data every 100ms (10fps)
Because we make use of a joystick, which is permanently used by the user and feels the worst if it doesn’t work properly, the most sensible thing to do at first is sending the input with the max fps allowed. The big problem here is that especially when a button is pressed the player can feel this delay.
Pros
- Fastest possible stable input
Cons
- Buttons aren’t responsive
- Joystick data no equal to data when button was pressed
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 100ms | 100ms | ||
Joystick change | 10 | 10 | 100ms | 100ms |
Quick joystick change | 100ms | 100ms |
Sending data every 125ms (8fps) and send 2 buttons/sec immediately
Because having to wait 100ms + send delay + 1 frame before the game notices that you pressed jump doesn’t really feel good, we changed the fps of the joystick to 8 so we had 2 fps to send a button when it’s pressed. Of course we also send the joystick data with the button data.
Pros
- Button input is now as fast as possible
- Joystick data equal to data when button was pressed
Cons
- Joystick becomes less responsive
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 0 | 2 | 1ms | 1ms |
Joystick change | 8 | 8 | 125ms | 125ms |
Quick joystick change | 125ms | 125ms |
Reset joystick timer when button send
With the previous rules the following could happen; 124ms after the last data was send we press a button after which the joystick and button data get send. Then 1ms later it’s been 125ms since the last joystick data was send so it gets send again. Since that isn’t needed we can optimize the data send by resetting the last send timer for the joystick
Pros
- Button input is now as fast as possible
- Joystick data equal to data when button was pressed
- Possible room for extra button when joystick fps is saved by resetting timer
Cons
- Joystick not responsive
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 0 | 2 + joystick send saved | 1ms | 1ms |
Joystick change | 8 – saved by button send | 8 | 125ms | 125ms |
Quick joystick change | 125ms | 125ms |
Only send data when direction angle difference > X
When playing I noticed that in general a user doesn’t change the joystick all the time but quite often has the joystick pointed in the same direction for a while. By making sure that we don’t send (almost) identical data we can save 1 or 2 sending every second. (which leaves more room for buttons)
Pros
- Button input is now as fast as possible
- Joystick data equal to data when button was pressed
- Possible room for extra button when joystick fps is saved by resetting timer
- Possible room for extra button when joystick fps is saved by not sending duplicate data
Cons
- Joystick not responsive
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 0 | 2 + joystick send saved | 1ms | 1ms |
Joystick change | 8 – saved by button send – saved by duplicate data | 8 | 125ms | 125ms |
Quick joystick change | 125ms | 125ms |
Don’t reset the last send timer when the data isn’t send because the angle was lower than X degree
The biggest problem that we currently have is that the joystick still has a fastest response time of 125ms (except when send with a button). We can lower the ‘best delay’ of the joystick to 1ms if we don’t reset the last send timer but instead just keep waiting when the angle difference between the last set angle is > X.
Pros
- Button input is now as fast as possible
- Joystick data equal to data when button was pressed
- Possible room for extra button when joystick fps is saved by resetting timer
- Possible room for extra button when joystick fps is saved by not sending duplicate data
- Certain cases where the joystick input becomes more responsive
Cons
- Joystick not responsive
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 0 | 2 + joystick send saved | 1ms | 1ms |
Joystick change | 8 – saved by button send – saved by duplicate data | 8 | 125ms | 1ms |
Quick joystick change | 125ms | 1ms |
Immediately send data when big angle change is detected
When playing the game with the previous rules feels much better than what we started with but there is still something that we must improve to make the game feel as good as we can; When doing a big change in direction it’s most notable that there’s a delay in what direction the character is going, since the delay can still be 124ms + delay + 1fps worst case. In order to fix this we handle the joystick input the same as a button when a big change in direction is detected.
Pros
- Button input is now as fast as possible
- Joystick data equal to data when button was pressed
- Possible room for extra button when joystick fps is saved by resetting timer
- Possible room for extra button when joystick fps is saved by not sending duplicate data
- Certain cases where the joystick input becomes more responsive
- Quick direction changes are send immediately
Cons
- Still not truely 60fps?
Min fps | Max fps | Worst delay | Best delay | |
---|---|---|---|---|
Button press | 0 | 2 + joystick send saved | 1ms | 1ms |
Joystick change | 8 – saved by button send – saved by duplicate data | 8 | 125ms | 1ms |
Quick joystick change | 1ms | 1ms |
2. Adjusting gameplay
Dealing with input delay
When playing the game it became apparent that navigating through the levels was quite hard because of the input delay, most notably it caused the players to just walk of platforms instead of jumping off the end. The fact that a virtual joystick isn’t as accurate as a normal joystick also made it much harder to navigate through the levels, especially because it would happen quite often that we would just hit the end of a platform when dashing.
Fixing the jump
In order to fix the jump we implemented some techniques described in this excelent blog by Yoann Pignole on Gamasutra. Most notable the “remember to jump” and the “still jump after drop” fixed the problems that we had.
Fixing the dash
In order to fix the dash we implemented Aim help in the game. When the user performs a dash we do a raycast in that direction, if the player is about to dash into a wall/platform but this can be prevented by a couple of degree that’s the direction the player jumps.
Redesigning the levels
Even with the jump and dash help it was still quite hard to navigate through the original Basher Beatdown levels (which were designed for the PC version with controllers. We decided to create special levels for AirConsole that included easier gameplay and that were easier to navigate by making bigger platforms and leaving bigger gaps between them. You can see the difference clearly in the below level comparison:
The original level
The AirConsole version