Skip to content

Commit

Permalink
Add ingame touch controls
Browse files Browse the repository at this point in the history
Add new client component `CTouchControls` for playing the game with touch inputs. The touch controls can be enabled/disabled with the config variable `cl_touch_controls`, which defaults to 1 on Android and 0 on other platforms. The touch controls consist of various on-screen touch buttons. The buttons are only shown when they are usable depending on the context.

Movement buttons for Left, Right and Jump actions are arranged in a `⊥`-pattern similar to WASD controls.

For the fire and hook action, two modes are implemented:

1. Direct touch input: the mouse is moved exactly where the player touches on the screen.
2. Virtual joystick: a button is used to emulate a joystick, which moves the mouse relative to the player.

In either mode, a button is used to switch between the active actions (fire and hook). While the virtual joystick is being held down, this button uses the other action directly instead of switching it.

The direct touch input can be enabled/disabled separately for ingame/spectating, to prevent accidental direct touch input when using a joystick.

When spectating, direct touch input is used to allow panning the map directly like in an image/map viewer. Joysticks can also be used to pan the map while spectating.

Two separate buttons are shown to switch to the previous and next weapons.

A hamburger menu button `☰` is used to toggle the visibility of lesser used touch buttons. This includes buttons for showing the scoreboard, showing the emoticon HUD, showing the spectator HUD, opening team and team chat, voting yes/no, and zooming. Once the dummy is connected, a button for swapping between main and dummy is shown. Long pressing the hamburger menu button will open the regular menu.

The emoticon and spectator HUDs are activated with the respective touch buttons and can be deactivated by touching outside of them or by using the back-button, as toggling them while the ingame touch button is pressed down is currently not feasible and also inconvenient at least for using the spectator HUD.

The default button layout described above is loaded from `data/touch_controls.json`. This layout can be overridden by creating `touch_controls.json` in the user directory. The following button properties are adjustable:

- Position and size: the X/Y position and width/height are integers on a 1,000,000² grid. The unit grid values are converted to screen grid values at runtime in relation to the aspect ratio of the screen. This means buttons may appear stretched if the resolution is changed, instead of buttons appearing outside the screen or not being aligned with the right side.
- Shape: rectangle or circle.
- Visibility: an array of predefined visibility classes can be selected and the button is only shown if all conditions are met. An empty array means that the button is always shown.
- Behavior: either predefined (hard-coded) behavior identified by an ID, or generic console commands (binds). Predefined behavior is only used where necessary, all other buttons are represented as generic binds.

In addition to the separate on-screen touch controls, a second row is added to the main page of the ingame menu when `cl_touch_controls` is enabled for less frequently used functions which are otherwise not usable without a keyboard:

- Checkbox for toggling the virtual joystick (temporary until controls can be adjusted more generically).
- Checkbox for toggling entities.
- Buttons to open the local and remote consoles.
- Button to close the menu (more convenient than using the back button if it's not always shown).

Currently missing:

- UI for adjusting the button layout.
- Various decisions and code cleanup TODOs in `CTouchControls`.
  • Loading branch information
Robyt3 committed Aug 17, 2024
1 parent b16bc40 commit 8efb45f
Show file tree
Hide file tree
Showing 21 changed files with 1,858 additions and 57 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,7 @@ set(EXPECTED_DATA
themes/winter.png
themes/winter_day.map
themes/winter_night.map
touch_controls.json
wordlist.txt
)

Expand Down Expand Up @@ -2395,6 +2396,8 @@ if(CLIENT)
components/statboard.h
components/tooltips.cpp
components/tooltips.h
components/touch_controls.cpp
components/touch_controls.h
components/voting.cpp
components/voting.h
gameclient.cpp
Expand Down
292 changes: 292 additions & 0 deletions data/touch_controls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
{
"direct-touch-ingame": true,
"direct-touch-spectate": true,
"touch-buttons": [
{
"x": 0,
"y": 833333,
"w": 200000,
"h": 166667,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "bind",
"label": "Left",
"command": "+left"
}
},
{
"x": 200000,
"y": 833333,
"w": 200000,
"h": 166667,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "bind",
"label": "Right",
"command": "+right"
}
},
{
"x": 100000,
"y": 666667,
"w": 200000,
"h": 166667,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "bind",
"label": "Jump",
"command": "+jump"
}
},
{
"x": 116667,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "bind",
"label": "← Weapon",
"command": "+prevweapon"
}
},
{
"x": 200000,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "bind",
"label": "Weapon →",
"command": "+nextweapon"
}
},
{
"x": 16667,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
],
"behavior": {
"type": "predefined",
"id": "extra-menu"
}
},
{
"x": 300000,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
"extra-menu",
"zoom-allowed"
],
"behavior": {
"type": "bind",
"label": "Zoom out",
"command": "zoom-"
}
},
{
"x": 383333,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
"extra-menu",
"zoom-allowed"
],
"behavior": {
"type": "bind",
"label": "Default zoom",
"command": "zoom"
}
},
{
"x": 466667,
"y": 16667,
"w": 83333,
"h": 83333,
"shape": "rect",
"visibilities": [
"extra-menu",
"zoom-allowed"
],
"behavior": {
"type": "bind",
"label": "Zoom in",
"command": "zoom+"
}
},
{
"x": 16667,
"y": 133333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"extra-menu"
],
"behavior": {
"type": "bind",
"label": "Scoreboard",
"command": "+scoreboard"
}
},
{
"x": 116667,
"y": 133333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"ingame",
"extra-menu"
],
"behavior": {
"type": "predefined",
"id": "emoticon"
}
},
{
"x": 116667,
"y": 133333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"spectate",
"extra-menu"
],
"behavior": {
"type": "predefined",
"id": "spectate"
}
},
{
"x": 216667,
"y": 133333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"extra-menu"
],
"behavior": {
"type": "bind",
"label": "Chat",
"command": "chat all"
}
},
{
"x": 316667,
"y": 133333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"extra-menu"
],
"behavior": {
"type": "bind",
"label": "Chat team",
"command": "chat team"
}
},
{
"x": 16667,
"y": 333333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"extra-menu",
"vote-active"
],
"behavior": {
"type": "bind",
"label": "Vote yes",
"command": "vote yes"
}
},
{
"x": 116667,
"y": 333333,
"w": 83333,
"h": 66667,
"shape": "rect",
"visibilities": [
"extra-menu",
"vote-active"
],
"behavior": {
"type": "bind",
"label": "Vote no",
"command": "vote no"
}
},
{
"x": 766667,
"y": 16667,
"w": 100000,
"h": 100000,
"shape": "rect",
"visibilities": [
"dummy-connected"
],
"behavior": {
"type": "bind",
"label": "Toggle dummy",
"command": "toggle cl_dummy 0 1"
}
},
{
"x": 883333,
"y": 16667,
"w": 100000,
"h": 100000,
"shape": "rect",
"visibilities": [
"ingame"
],
"behavior": {
"type": "predefined",
"id": "swap-action"
}
},
{
"x": 750000,
"y": 583333,
"w": 233333,
"h": 400000,
"shape": "circle",
"visibilities": [
"joystick"
],
"behavior": {
"type": "predefined",
"id": "joystick-action"
}
}
]
}
13 changes: 9 additions & 4 deletions src/engine/client/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,14 @@ const std::vector<IInput::CTouchFingerState> &CInput::TouchFingerStates() const
return m_vTouchFingerStates;
}

void CInput::ClearTouchDeltas()
{
for(CTouchFingerState &TouchFingerState : m_vTouchFingerStates)
{
TouchFingerState.m_Delta = vec2(0.0f, 0.0f);
}
}

const char *CInput::GetClipboardText()
{
SDL_free(m_pClipboardText);
Expand Down Expand Up @@ -349,10 +357,7 @@ void CInput::Clear()
mem_zero(m_aInputState, sizeof(m_aInputState));
mem_zero(m_aInputCount, sizeof(m_aInputCount));
m_vInputEvents.clear();
for(CTouchFingerState &TouchFingerState : m_vTouchFingerStates)
{
TouchFingerState.m_Delta = vec2(0.0f, 0.0f);
}
ClearTouchDeltas();
}

float CInput::GetUpdateTime() const
Expand Down
1 change: 1 addition & 0 deletions src/engine/client/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ class CInput : public IEngineInput
bool NativeMousePressed(int Index) const override;

const std::vector<CTouchFingerState> &TouchFingerStates() const override;
void ClearTouchDeltas() override;

const char *GetClipboardText() override;
void SetClipboardText(const char *pText) override;
Expand Down
6 changes: 6 additions & 0 deletions src/engine/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ class IInput : public IInterface
* @return vector of all touch finger states
*/
virtual const std::vector<CTouchFingerState> &TouchFingerStates() const = 0;
/**
* Must be called after the touch finger states have been used during the client update to ensure that
* touch deltas are only accumulated until the next update. If the touch states are only using during
* rendering, i.e. for user interfaces, then this is called automatically by calling @link Clear @endlink.
*/
virtual void ClearTouchDeltas() = 0;

// clipboard
virtual const char *GetClipboardText() = 0;
Expand Down
6 changes: 6 additions & 0 deletions src/engine/shared/config_variables.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ MACRO_CONFIG_INT(ClAntiPingSmooth, cl_antiping_smooth, 0, 0, 1, CFGFLAG_CLIENT |
MACRO_CONFIG_INT(ClAntiPingGunfire, cl_antiping_gunfire, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Predict gunfire and show predicted weapon physics (with cl_antiping_grenade 1 and cl_antiping_weapons 1)")
MACRO_CONFIG_INT(ClPredictionMargin, cl_prediction_margin, 10, 1, 300, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Prediction margin in ms (adds latency, can reduce lag from ping jumps)")
MACRO_CONFIG_INT(ClSubTickAiming, cl_sub_tick_aiming, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Send aiming data at sub-tick accuracy")
#if defined(CONF_PLATFORM_ANDROID)
MACRO_CONFIG_INT(ClTouchControls, cl_touch_controls, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable ingame touch controls")
#else
MACRO_CONFIG_INT(ClTouchControls, cl_touch_controls, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Enable ingame touch controls")
#endif
MACRO_CONFIG_INT(ClTouchControlsJoystick, cl_touch_controls_joystick, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Use virtual joystick for ingame touch controls")

MACRO_CONFIG_INT(ClNameplates, cl_nameplates, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show name plates")
MACRO_CONFIG_INT(ClAfkEmote, cl_afk_emote, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show zzz emote next to afk players")
Expand Down
8 changes: 8 additions & 0 deletions src/game/client/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,14 @@ class CComponent
* @param Event The input event.
*/
virtual bool OnInput(const IInput::CEvent &Event) { return false; }
/**
* Called with all current touch finger states.
*
* @param vTouchFingerStates The touch finger states to be handled.
*
* @return `true` if the component used the touch events, `false` otherwise
*/
virtual bool OnTouchState(const std::vector<IInput::CTouchFingerState> &vTouchFingerStates) { return false; }
};

#endif
2 changes: 1 addition & 1 deletion src/game/client/components/controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@

class CControls : public CComponent
{
public:
float GetMinMouseDistance() const;
float GetMaxMouseDistance() const;

public:
vec2 m_aMousePos[NUM_DUMMIES];
vec2 m_aMousePosOnAction[NUM_DUMMIES];
vec2 m_aTargetPos[NUM_DUMMIES];
Expand Down
Loading

0 comments on commit 8efb45f

Please sign in to comment.