diff --git a/Source/Engine/Input/Gamepad.cpp b/Source/Engine/Input/Gamepad.cpp index f4a2ef4ab..32856839b 100644 --- a/Source/Engine/Input/Gamepad.cpp +++ b/Source/Engine/Input/Gamepad.cpp @@ -2,6 +2,71 @@ #include "Gamepad.h" +namespace +{ + GamepadAxis GetButtonAxis(GamepadButton button, bool& positive) + { + positive = true; + switch (button) + { + case GamepadButton::LeftTrigger: + return GamepadAxis::LeftTrigger; + case GamepadButton::RightTrigger: + return GamepadAxis::RightTrigger; + case GamepadButton::LeftStickUp: + return GamepadAxis::LeftStickY; + case GamepadButton::LeftStickDown: + positive = false; + return GamepadAxis::LeftStickY; + case GamepadButton::LeftStickLeft: + positive = false; + return GamepadAxis::LeftStickX; + case GamepadButton::LeftStickRight: + return GamepadAxis::LeftStickX; + case GamepadButton::RightStickUp: + return GamepadAxis::RightStickY; + case GamepadButton::RightStickDown: + positive = false; + return GamepadAxis::RightStickY; + case GamepadButton::RightStickLeft: + positive = false; + return GamepadAxis::RightStickX; + case GamepadButton::RightStickRight: + return GamepadAxis::RightStickX; + default: + return GamepadAxis::None; + } + } + + bool GetButtonState(const Gamepad::State& state, GamepadButton button, float deadZone) + { + if (deadZone > 0.01f) + { + switch (button) + { + case GamepadButton::LeftTrigger: + case GamepadButton::RightTrigger: + case GamepadButton::LeftStickUp: + case GamepadButton::LeftStickDown: + case GamepadButton::LeftStickLeft: + case GamepadButton::LeftStickRight: + case GamepadButton::RightStickUp: + case GamepadButton::RightStickDown: + case GamepadButton::RightStickLeft: + case GamepadButton::RightStickRight: + { + bool positive; + float axis = state.Axis[(int32)GetButtonAxis(button, positive)]; + return positive ? axis >= deadZone : axis <= -deadZone; + } + default: + break; + } + } + return state.Buttons[(int32)button]; + } +} + void GamepadLayout::Init() { for (int32 i = 0; i < (int32)GamepadButton::MAX; i++) @@ -31,6 +96,21 @@ void Gamepad::ResetState() _mappedPrevState.Clear(); } +bool Gamepad::GetButton(GamepadButton button, float deadZone) const +{ + return GetButtonState(_mappedState, button, deadZone); +} + +bool Gamepad::GetButtonDown(GamepadButton button, float deadZone) const +{ + return GetButtonState(_mappedState, button, deadZone) && !GetButtonState(_mappedPrevState, button, deadZone); +} + +bool Gamepad::GetButtonUp(GamepadButton button, float deadZone) const +{ + return !GetButtonState(_mappedState, button, deadZone) && GetButtonState(_mappedPrevState, button, deadZone); +} + bool Gamepad::IsAnyButtonDown() const { // TODO: optimize with SIMD diff --git a/Source/Engine/Input/Gamepad.h b/Source/Engine/Input/Gamepad.h index 20994d85a..dc95c67ae 100644 --- a/Source/Engine/Input/Gamepad.h +++ b/Source/Engine/Input/Gamepad.h @@ -148,36 +148,30 @@ public: /// Gets the gamepad button state (true if being pressed during the current frame). /// /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user holds down the button, otherwise false. - API_FUNCTION() FORCE_INLINE bool GetButton(const GamepadButton button) const - { - return _mappedState.Buttons[static_cast(button)]; - } + API_FUNCTION() bool GetButton(GamepadButton button, float deadZone = 0.0f) const; /// /// Gets the gamepad button down state (true if was pressed during the current frame). /// /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user starts pressing down the button, otherwise false. - API_FUNCTION() FORCE_INLINE bool GetButtonDown(const GamepadButton button) const - { - return _mappedState.Buttons[static_cast(button)] && !_mappedPrevState.Buttons[static_cast(button)]; - } - - /// - /// Checks if any gamepad button is currently pressed. - /// - API_PROPERTY() bool IsAnyButtonDown() const; + API_FUNCTION() bool GetButtonDown(GamepadButton button, float deadZone = 0.0f) const; /// /// Gets the gamepad button up state (true if was released during the current frame). /// /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user releases the button, otherwise false. - API_FUNCTION() FORCE_INLINE bool GetButtonUp(const GamepadButton button) const - { - return !_mappedState.Buttons[static_cast(button)] && _mappedPrevState.Buttons[static_cast(button)]; - } + API_FUNCTION() bool GetButtonUp(GamepadButton button, float deadZone = 0.0f) const; + + /// + /// Checks if any gamepad button is currently pressed. + /// + API_PROPERTY() bool IsAnyButtonDown() const; public: /// diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp index 7048140ef..c95d7b03e 100644 --- a/Source/Engine/Input/Input.cpp +++ b/Source/Engine/Input/Input.cpp @@ -120,6 +120,7 @@ void InputSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* m config.MouseButton = JsonTools::GetEnum(v, "MouseButton", MouseButton::None); config.GamepadButton = JsonTools::GetEnum(v, "GamepadButton", GamepadButton::None); config.Gamepad = JsonTools::GetEnum(v, "Gamepad", InputGamepadIndex::All); + config.DeadZone = JsonTools::GetFloat(v, "DeadZone", 0.5f); } } else @@ -499,24 +500,24 @@ float Input::GetGamepadAxis(int32 gamepadIndex, GamepadAxis axis) return 0.0f; } -bool Input::GetGamepadButton(int32 gamepadIndex, GamepadButton button) +bool Input::GetGamepadButton(int32 gamepadIndex, GamepadButton button, float deadZone) { if (gamepadIndex >= 0 && gamepadIndex < Gamepads.Count()) - return Gamepads[gamepadIndex]->GetButton(button); + return Gamepads[gamepadIndex]->GetButton(button, deadZone); return false; } -bool Input::GetGamepadButtonDown(int32 gamepadIndex, GamepadButton button) +bool Input::GetGamepadButtonDown(int32 gamepadIndex, GamepadButton button, float deadZone) { if (gamepadIndex >= 0 && gamepadIndex < Gamepads.Count()) - return Gamepads[gamepadIndex]->GetButtonDown(button); + return Gamepads[gamepadIndex]->GetButtonDown(button, deadZone); return false; } -bool Input::GetGamepadButtonUp(int32 gamepadIndex, GamepadButton button) +bool Input::GetGamepadButtonUp(int32 gamepadIndex, GamepadButton button, float deadZone) { if (gamepadIndex >= 0 && gamepadIndex < Gamepads.Count()) - return Gamepads[gamepadIndex]->GetButtonUp(button); + return Gamepads[gamepadIndex]->GetButtonUp(button, deadZone); return false; } @@ -542,13 +543,13 @@ float Input::GetGamepadAxis(InputGamepadIndex gamepad, GamepadAxis axis) return false; } -bool Input::GetGamepadButton(InputGamepadIndex gamepad, GamepadButton button) +bool Input::GetGamepadButton(InputGamepadIndex gamepad, GamepadButton button, float deadZone) { if (gamepad == InputGamepadIndex::All) { for (auto g : Gamepads) { - if (g->GetButton(button)) + if (g->GetButton(button, deadZone)) return true; } } @@ -556,18 +557,18 @@ bool Input::GetGamepadButton(InputGamepadIndex gamepad, GamepadButton button) { const auto index = static_cast(gamepad); if (index < Gamepads.Count()) - return Gamepads[index]->GetButton(button); + return Gamepads[index]->GetButton(button, deadZone); } return false; } -bool Input::GetGamepadButtonDown(InputGamepadIndex gamepad, GamepadButton button) +bool Input::GetGamepadButtonDown(InputGamepadIndex gamepad, GamepadButton button, float deadZone) { if (gamepad == InputGamepadIndex::All) { for (auto g : Gamepads) { - if (g->GetButtonDown(button)) + if (g->GetButtonDown(button, deadZone)) return true; } } @@ -575,18 +576,18 @@ bool Input::GetGamepadButtonDown(InputGamepadIndex gamepad, GamepadButton button { const auto index = static_cast(gamepad); if (index < Gamepads.Count()) - return Gamepads[index]->GetButtonDown(button); + return Gamepads[index]->GetButtonDown(button, deadZone); } return false; } -bool Input::GetGamepadButtonUp(InputGamepadIndex gamepad, GamepadButton button) +bool Input::GetGamepadButtonUp(InputGamepadIndex gamepad, GamepadButton button, float deadZone) { if (gamepad == InputGamepadIndex::All) { for (auto g : Gamepads) { - if (g->GetButtonUp(button)) + if (g->GetButtonUp(button, deadZone)) return true; } } @@ -594,7 +595,7 @@ bool Input::GetGamepadButtonUp(InputGamepadIndex gamepad, GamepadButton button) { const auto index = static_cast(gamepad); if (index < Gamepads.Count()) - return Gamepads[index]->GetButtonUp(button); + return Gamepads[index]->GetButtonUp(button, deadZone); } return false; } @@ -1065,26 +1066,26 @@ void InputService::Update() bool isActive; if (config.Mode == InputActionMode::Pressing) { - isActive = Input::GetKey(config.Key) || Input::GetMouseButton(config.MouseButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadButton); + isActive = Input::GetKey(config.Key) || Input::GetMouseButton(config.MouseButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadButton, config.DeadZone); } else if (config.Mode == InputActionMode::Press) { - isActive = Input::GetKeyDown(config.Key) || Input::GetMouseButtonDown(config.MouseButton) || Input::GetGamepadButtonDown(config.Gamepad, config.GamepadButton); + isActive = Input::GetKeyDown(config.Key) || Input::GetMouseButtonDown(config.MouseButton) || Input::GetGamepadButtonDown(config.Gamepad, config.GamepadButton, config.DeadZone); } else { - isActive = Input::GetKeyUp(config.Key) || Input::GetMouseButtonUp(config.MouseButton) || Input::GetGamepadButtonUp(config.Gamepad, config.GamepadButton); + isActive = Input::GetKeyUp(config.Key) || Input::GetMouseButtonUp(config.MouseButton) || Input::GetGamepadButtonUp(config.Gamepad, config.GamepadButton, config.DeadZone); } - if (Input::GetKeyDown(config.Key) || Input::GetMouseButtonDown(config.MouseButton) || Input::GetGamepadButtonDown(config.Gamepad, config.GamepadButton)) + if (Input::GetKeyDown(config.Key) || Input::GetMouseButtonDown(config.MouseButton) || Input::GetGamepadButtonDown(config.Gamepad, config.GamepadButton, config.DeadZone)) { data.State = InputActionState::Press; } - else if (Input::GetKey(config.Key) || Input::GetMouseButton(config.MouseButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadButton)) + else if (Input::GetKey(config.Key) || Input::GetMouseButton(config.MouseButton) || Input::GetGamepadButton(config.Gamepad, config.GamepadButton, config.DeadZone)) { data.State = InputActionState::Pressing; } - else if (Input::GetKeyUp(config.Key) || Input::GetMouseButtonUp(config.MouseButton) || Input::GetGamepadButtonUp(config.Gamepad, config.GamepadButton)) + else if (Input::GetKeyUp(config.Key) || Input::GetMouseButtonUp(config.MouseButton) || Input::GetGamepadButtonUp(config.Gamepad, config.GamepadButton, config.DeadZone)) { data.State = InputActionState::Release; } diff --git a/Source/Engine/Input/Input.h b/Source/Engine/Input/Input.h index 73e87f5f0..dca26a5f4 100644 --- a/Source/Engine/Input/Input.h +++ b/Source/Engine/Input/Input.h @@ -238,24 +238,27 @@ public: /// /// The gamepad index /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user holds down the button, otherwise false. - API_FUNCTION() static bool GetGamepadButton(int32 gamepadIndex, GamepadButton button); + API_FUNCTION() static bool GetGamepadButton(int32 gamepadIndex, GamepadButton button, float deadZone = 0.0f); /// /// Gets the gamepad button down state (true if was pressed during the current frame). /// /// The gamepad index /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user starts pressing down the button, otherwise false. - API_FUNCTION() static bool GetGamepadButtonDown(int32 gamepadIndex, GamepadButton button); + API_FUNCTION() static bool GetGamepadButtonDown(int32 gamepadIndex, GamepadButton button, float deadZone = 0.0f); /// /// Gets the gamepad button up state (true if was released during the current frame). /// /// The gamepad index /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user releases the button, otherwise false. - API_FUNCTION() static bool GetGamepadButtonUp(int32 gamepadIndex, GamepadButton button); + API_FUNCTION() static bool GetGamepadButtonUp(int32 gamepadIndex, GamepadButton button, float deadZone = 0.0f); /// /// Gets the gamepad axis value. @@ -270,24 +273,27 @@ public: /// /// The gamepad /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user holds down the button, otherwise false. - API_FUNCTION() static bool GetGamepadButton(InputGamepadIndex gamepad, GamepadButton button); + API_FUNCTION() static bool GetGamepadButton(InputGamepadIndex gamepad, GamepadButton button, float deadZone = 0.0f); /// /// Gets the gamepad button down state (true if was pressed during the current frame). /// /// The gamepad /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user starts pressing down the button, otherwise false. - API_FUNCTION() static bool GetGamepadButtonDown(InputGamepadIndex gamepad, GamepadButton button); + API_FUNCTION() static bool GetGamepadButtonDown(InputGamepadIndex gamepad, GamepadButton button, float deadZone = 0.0f); /// /// Gets the gamepad button up state (true if was released during the current frame). /// /// The gamepad /// Gamepad button to check + /// Custom dead-zone value to detect gamepad button usage for non-binary buttons such as left/right thumbs that can move freely. By default, any movement is registered. /// True if user releases the button, otherwise false. - API_FUNCTION() static bool GetGamepadButtonUp(InputGamepadIndex gamepad, GamepadButton button); + API_FUNCTION() static bool GetGamepadButtonUp(InputGamepadIndex gamepad, GamepadButton button, float deadZone = 0.0f); public: /// diff --git a/Source/Engine/Input/VirtualInput.h b/Source/Engine/Input/VirtualInput.h index 817d7014c..a4975aaef 100644 --- a/Source/Engine/Input/VirtualInput.h +++ b/Source/Engine/Input/VirtualInput.h @@ -48,6 +48,12 @@ API_STRUCT() struct ActionConfig /// API_FIELD(Attributes="EditorOrder(40)") InputGamepadIndex Gamepad; + + /// + /// Threshold for non-binary value inputs such as gamepad stick position to decide if action was triggered. Can be sued to activate action only if input value is higher than specified number. + /// + API_FIELD(Attributes = "EditorOrder(50)") + float DeadZone = 0.5f; }; ///