diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-28 22:52:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-28 22:52:09 +1000 |
commit | 0b7ddd05d19fa320b25ad0f5c968852dc416583d (patch) | |
tree | 82dcdaa98157a22c453af124091957dbf162f56c | |
parent | 0886098242be9e41f351519f8a5958995e8ed9ab (diff) |
Add extremely basic controller support (only movement)
-rw-r--r-- | source/application/StarInputEvent.cpp | 34 | ||||
-rw-r--r-- | source/application/StarInputEvent.hpp | 46 | ||||
-rw-r--r-- | source/application/StarMainApplication_sdl.cpp | 158 | ||||
-rw-r--r-- | source/client/StarClientApplication.cpp | 15 | ||||
-rw-r--r-- | source/client/StarClientApplication.hpp | 2 | ||||
-rw-r--r-- | source/game/StarActorMovementController.cpp | 9 | ||||
-rw-r--r-- | source/game/StarActorMovementController.hpp | 5 | ||||
-rw-r--r-- | source/game/StarPlayer.cpp | 26 | ||||
-rw-r--r-- | source/game/StarPlayer.hpp | 2 |
9 files changed, 236 insertions, 61 deletions
diff --git a/source/application/StarInputEvent.cpp b/source/application/StarInputEvent.cpp index 650344a..7d6835b 100644 --- a/source/application/StarInputEvent.cpp +++ b/source/application/StarInputEvent.cpp @@ -163,4 +163,38 @@ EnumMap<MouseWheel> const MouseWheelNames{ {MouseWheel::Down, "MouseWheelDown"} }; +EnumMap<ControllerAxis> const ControllerAxisNames{ + {ControllerAxis::LeftX, "LeftX"}, + {ControllerAxis::LeftY, "LeftY"}, + {ControllerAxis::RightX, "RightX"}, + {ControllerAxis::RightY, "RightY"}, + {ControllerAxis::TriggerLeft, "TriggerLeft"}, + {ControllerAxis::TriggerRight, "TriggerRight"}, +}; + +EnumMap<ControllerButton> const ControllerButtonNames{ + {ControllerButton::A, "A"}, + {ControllerButton::B, "B"}, + {ControllerButton::X, "X"}, + {ControllerButton::Y, "Y"}, + {ControllerButton::Back, "Back"}, + {ControllerButton::Guide, "Guide"}, + {ControllerButton::Start, "Start"}, + {ControllerButton::LeftStick, "LeftStick"}, + {ControllerButton::RightStick, "RightStick"}, + {ControllerButton::LeftShoulder, "LeftShoulder"}, + {ControllerButton::RightShoulder, "RightShoulder"}, + {ControllerButton::DPadUp, "DPadUp"}, + {ControllerButton::DPadDown, "DPadDown"}, + {ControllerButton::DPadLeft, "DPadLeft"}, + {ControllerButton::DPadRight, "DPadRight"}, + {ControllerButton::Misc1, "Misc1"}, + {ControllerButton::Paddle1, "Paddle1"}, + {ControllerButton::Paddle2, "Paddle2"}, + {ControllerButton::Paddle3, "Paddle3"}, + {ControllerButton::Paddle4, "Paddle4"}, + {ControllerButton::Touchpad, "Touchpad"}, + {ControllerButton::Invalid, "Invalid"} +}; + } diff --git a/source/application/StarInputEvent.hpp b/source/application/StarInputEvent.hpp index bbf46b5..896b192 100644 --- a/source/application/StarInputEvent.hpp +++ b/source/application/StarInputEvent.hpp @@ -154,7 +154,8 @@ enum class KeyMod : uint16_t { RGui = 0x0800, Num = 0x1000, Caps = 0x2000, - AltGr = 0x4000 + AltGr = 0x4000, + Scroll = 0x8000 }; extern EnumMap<KeyMod> const KeyModNames; @@ -181,6 +182,43 @@ extern EnumMap<MouseWheel> const MouseWheelNames; typedef uint32_t ControllerId; +enum class ControllerAxis : uint8_t { + LeftX, + LeftY, + RightX, + RightY, + TriggerLeft, + TriggerRight, + Invalid = 255 +}; +extern EnumMap<ControllerAxis> const ControllerAxisNames; + +enum class ControllerButton : uint8_t { + A, + B, + X, + Y, + Back, + Guide, + Start, + LeftStick, + RightStick, + LeftShoulder, + RightShoulder, + DPadUp, + DPadDown, + DPadLeft, + DPadRight, + Misc1, + Paddle1, + Paddle2, + Paddle3, + Paddle4, + Touchpad, + Invalid = 255 +}; +extern EnumMap<ControllerButton> const ControllerButtonNames; + struct KeyDownEvent { Key key; KeyMod mods; @@ -216,18 +254,18 @@ struct MouseWheelEvent { struct ControllerAxisEvent { ControllerId controller; - unsigned controllerAxis; + ControllerAxis controllerAxis; float controllerAxisValue; }; struct ControllerButtonDownEvent { ControllerId controller; - unsigned controllerButton; + ControllerButton controllerButton; }; struct ControllerButtonUpEvent { ControllerId controller; - unsigned controllerButton; + ControllerButton controllerButton; }; typedef Variant< diff --git a/source/application/StarMainApplication_sdl.cpp b/source/application/StarMainApplication_sdl.cpp index d03e141..818cada 100644 --- a/source/application/StarMainApplication_sdl.cpp +++ b/source/application/StarMainApplication_sdl.cpp @@ -151,45 +151,56 @@ Maybe<Key> keyFromSdlKeyCode(SDL_Keycode sym) { } KeyMod keyModsFromSdlKeyMods(uint16_t mod) { - KeyMod keyMod = KeyMod::NoMod; - - if (mod & KMOD_LSHIFT) - keyMod |= KeyMod::LShift; - if (mod & KMOD_RSHIFT) - keyMod |= KeyMod::RShift; - if (mod & KMOD_LCTRL) - keyMod |= KeyMod::LCtrl; - if (mod & KMOD_RCTRL) - keyMod |= KeyMod::RCtrl; - if (mod & KMOD_LALT) - keyMod |= KeyMod::LAlt; - if (mod & KMOD_RALT) - keyMod |= KeyMod::RAlt; - if (mod & KMOD_LGUI) - keyMod |= KeyMod::LGui; - if (mod & KMOD_RGUI) - keyMod |= KeyMod::RGui; - if (mod & KMOD_NUM) - keyMod |= KeyMod::Num; - if (mod & KMOD_CAPS) - keyMod |= KeyMod::Caps; - if (mod & KMOD_MODE) - keyMod |= KeyMod::AltGr; - - return keyMod; + return static_cast<KeyMod>(mod); } MouseButton mouseButtonFromSdlMouseButton(uint8_t button) { - if (button == SDL_BUTTON_LEFT) - return MouseButton::Left; - else if (button == SDL_BUTTON_MIDDLE) - return MouseButton::Middle; - else if (button == SDL_BUTTON_RIGHT) - return MouseButton::Right; - else if (button == SDL_BUTTON_X1) - return MouseButton::FourthButton; - else - return MouseButton::FifthButton; + switch (button) { + case SDL_BUTTON_LEFT: return MouseButton::Left; + case SDL_BUTTON_MIDDLE: return MouseButton::Middle; + case SDL_BUTTON_RIGHT: return MouseButton::Right; + case SDL_BUTTON_X1: return MouseButton::FourthButton; + default: return MouseButton::FifthButton; + } +} + +ControllerAxis controllerAxisFromSdlControllerAxis(uint8_t axis) { + switch (axis) { + case SDL_CONTROLLER_AXIS_LEFTX: return ControllerAxis::LeftX; + case SDL_CONTROLLER_AXIS_LEFTY: return ControllerAxis::LeftY; + case SDL_CONTROLLER_AXIS_RIGHTX: return ControllerAxis::RightX; + case SDL_CONTROLLER_AXIS_RIGHTY: return ControllerAxis::RightY; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: return ControllerAxis::TriggerLeft; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: return ControllerAxis::TriggerRight; + default: return ControllerAxis::Invalid; + } +} + +ControllerButton controllerButtonFromSdlControllerButton(uint8_t button) { + switch (button) { + case SDL_CONTROLLER_BUTTON_A: return ControllerButton::A; + case SDL_CONTROLLER_BUTTON_B: return ControllerButton::B; + case SDL_CONTROLLER_BUTTON_X: return ControllerButton::X; + case SDL_CONTROLLER_BUTTON_Y: return ControllerButton::Y; + case SDL_CONTROLLER_BUTTON_BACK: return ControllerButton::Back; + case SDL_CONTROLLER_BUTTON_GUIDE: return ControllerButton::Guide; + case SDL_CONTROLLER_BUTTON_START: return ControllerButton::Start; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: return ControllerButton::LeftStick; + case SDL_CONTROLLER_BUTTON_RIGHTSTICK: return ControllerButton::RightStick; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: return ControllerButton::LeftShoulder; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: return ControllerButton::RightShoulder; + case SDL_CONTROLLER_BUTTON_DPAD_UP: return ControllerButton::DPadUp; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: return ControllerButton::DPadDown; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: return ControllerButton::DPadLeft; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: return ControllerButton::DPadRight; + case SDL_CONTROLLER_BUTTON_MISC1: return ControllerButton::Misc1; + case SDL_CONTROLLER_BUTTON_PADDLE1: return ControllerButton::Paddle1; + case SDL_CONTROLLER_BUTTON_PADDLE2: return ControllerButton::Paddle2; + case SDL_CONTROLLER_BUTTON_PADDLE3: return ControllerButton::Paddle3; + case SDL_CONTROLLER_BUTTON_PADDLE4: return ControllerButton::Paddle4; + case SDL_CONTROLLER_BUTTON_TOUCHPAD: return ControllerButton::Touchpad; + default: return ControllerButton::Invalid; + } } class SdlPlatform { @@ -233,9 +244,9 @@ public: if (SDL_InitSubSystem(SDL_INIT_VIDEO)) throw ApplicationException(strf("Couldn't initialize SDL Video: {}", SDL_GetError())); - Logger::info("Application: Initializing SDL Joystick"); - if (SDL_InitSubSystem(SDL_INIT_JOYSTICK)) - throw ApplicationException(strf("Couldn't initialize SDL Joystick: {}", SDL_GetError())); + Logger::info("Application: Initializing SDL Controller"); + if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER)) + throw ApplicationException(strf("Couldn't initialize SDL Controller: {}", SDL_GetError())); Logger::info("Application: Initializing SDL Sound"); if (SDL_InitSubSystem(SDL_INIT_AUDIO)) @@ -585,7 +596,8 @@ private: SDL_Event event; while (SDL_PollEvent(&event)) { Maybe<InputEvent> starEvent; - if (event.type == SDL_WINDOWEVENT) { + switch (event.type) { + case SDL_WINDOWEVENT: if (event.window.event == SDL_WINDOWEVENT_MAXIMIZED || event.window.event == SDL_WINDOWEVENT_RESTORED) { auto windowFlags = SDL_GetWindowFlags(m_sdlWindow); @@ -605,40 +617,71 @@ private: m_renderer->setScreenSize(m_windowSize); m_application->windowChanged(m_windowMode, m_windowSize); } - - } else if (event.type == SDL_KEYDOWN) { + break; + case SDL_KEYDOWN: if (!event.key.repeat) { if (auto key = keyFromSdlKeyCode(event.key.keysym.sym)) starEvent.set(KeyDownEvent{*key, keyModsFromSdlKeyMods(event.key.keysym.mod)}); } - - } else if (event.type == SDL_KEYUP) { + break; + case SDL_KEYUP: if (auto key = keyFromSdlKeyCode(event.key.keysym.sym)) starEvent.set(KeyUpEvent{*key}); - - } else if (event.type == SDL_TEXTINPUT) { + break; + case SDL_TEXTINPUT: starEvent.set(TextInputEvent{String(event.text.text)}); - - } else if (event.type == SDL_MOUSEMOTION) { + break; + case SDL_MOUSEMOTION: starEvent.set(MouseMoveEvent{ {event.motion.xrel, -event.motion.yrel}, {event.motion.x, (int)m_windowSize[1] - event.motion.y}}); - - } else if (event.type == SDL_MOUSEBUTTONDOWN) { + break; + case SDL_MOUSEBUTTONDOWN: starEvent.set(MouseButtonDownEvent{mouseButtonFromSdlMouseButton(event.button.button), {event.button.x, (int)m_windowSize[1] - event.button.y}}); - - } else if (event.type == SDL_MOUSEBUTTONUP) { + break; + case SDL_MOUSEBUTTONUP: starEvent.set(MouseButtonUpEvent{mouseButtonFromSdlMouseButton(event.button.button), {event.button.x, (int)m_windowSize[1] - event.button.y}}); - - } else if (event.type == SDL_MOUSEWHEEL) { + break; + case SDL_MOUSEWHEEL: int x, y; SDL_GetMouseState(&x, &y); starEvent.set(MouseWheelEvent{event.wheel.y < 0 ? MouseWheel::Down : MouseWheel::Up, {x, (int)m_windowSize[1] - y}}); - - } else if (event.type == SDL_QUIT) { + break; + case SDL_CONTROLLERAXISMOTION: + starEvent.set(ControllerAxisEvent{ + (ControllerId)event.caxis.which, + controllerAxisFromSdlControllerAxis(event.caxis.axis), + (float)event.caxis.value / 32768.0f + }); + break; + case SDL_CONTROLLERBUTTONDOWN: + starEvent.set(ControllerButtonDownEvent{ (ControllerId)event.cbutton.which, controllerButtonFromSdlControllerButton(event.cbutton.button) }); + break; + case SDL_CONTROLLERBUTTONUP: + starEvent.set(ControllerButtonUpEvent{ (ControllerId)event.cbutton.which, controllerButtonFromSdlControllerButton(event.cbutton.button) }); + break; + case SDL_CONTROLLERDEVICEADDED: + { + auto insertion = m_SdlControllers.insert_or_assign(event.cdevice.which, SDLGameControllerUPtr(SDL_GameControllerOpen(event.cdevice.which), SDL_GameControllerClose)); + if (SDL_GameController* controller = insertion.first->second.get()) + Logger::info("Controller device '{}' added", SDL_GameControllerName(controller)); + } + break; + case SDL_CONTROLLERDEVICEREMOVED: + { + auto find = m_SdlControllers.find(event.cdevice.which); + if (find != m_SdlControllers.end()) { + if (SDL_GameController* controller = find->second.get()) + Logger::info("Controller device '{}' removed", SDL_GameControllerName(controller)); + m_SdlControllers.erase(event.cdevice.which); + } + } + break; + case SDL_QUIT: m_quitRequested = true; starEvent.reset(); + break; } if (starEvent) @@ -744,6 +787,9 @@ private: SDL_GLContext m_sdlGlContext = nullptr; SDL_AudioDeviceID m_sdlAudioDevice = 0; + typedef std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> SDLGameControllerUPtr; + StableHashMap<int, SDLGameControllerUPtr> m_SdlControllers; + typedef std::unique_ptr<SDL_Surface, decltype(&SDL_FreeSurface)> SDLSurfaceUPtr; typedef std::unique_ptr<SDL_Cursor, decltype(&SDL_FreeCursor)> SDLCursorUPtr; struct CursorEntry { diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index 304fe61..fa8d97b 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -273,6 +273,16 @@ void ClientApplication::processInput(InputEvent const& event) { return KeyDownEvent{keyEvent.key, keyEvent.mods & ~*modKey}; }); } + else if (auto cAxis = event.ptr<ControllerAxisEvent>()) { + if (cAxis->controllerAxis == ControllerAxis::LeftX) + m_controllerLeftStick[0] = cAxis->controllerAxisValue; + else if (cAxis->controllerAxis == ControllerAxis::LeftY) + m_controllerLeftStick[1] = cAxis->controllerAxisValue; + else if (cAxis->controllerAxis == ControllerAxis::RightX) + m_controllerRightStick[0] = cAxis->controllerAxisValue; + else if (cAxis->controllerAxis == ControllerAxis::RightY) + m_controllerRightStick[1] = cAxis->controllerAxisValue; + } if (!m_errorScreen->accepted() && m_errorScreen->handleInputEvent(event)) return; @@ -755,6 +765,11 @@ void ClientApplication::updateRunning() { m_player->addEmote(HumanoidEmote::Sleep); } + if (m_controllerLeftStick.magnitudeSquared() > 0.001f) + m_player->setMoveVector(m_controllerLeftStick); + else + m_player->setMoveVector(Vec2F()); + auto checkDisconnection = [this]() { if (!m_universeClient->isConnected()) { m_cinematicOverlay->stop(); diff --git a/source/client/StarClientApplication.hpp b/source/client/StarClientApplication.hpp index 89f6a61..5e577e8 100644 --- a/source/client/StarClientApplication.hpp +++ b/source/client/StarClientApplication.hpp @@ -105,6 +105,8 @@ private: int m_maxInterfaceScale = 3; Vec2F m_crossoverRes; + Vec2F m_controllerLeftStick; + Vec2F m_controllerRightStick; List<KeyDownEvent> m_heldKeyEvents; List<KeyDownEvent> m_edgeKeyEvents; diff --git a/source/game/StarActorMovementController.cpp b/source/game/StarActorMovementController.cpp index 1b8f0e4..9dc9ef8 100644 --- a/source/game/StarActorMovementController.cpp +++ b/source/game/StarActorMovementController.cpp @@ -446,6 +446,7 @@ ActorMovementController::ActorMovementController(ActorMovementParameters const& m_lastControlJump = false; m_lastControlDown = false; m_targetHorizontalAmbulatingVelocity = 0.0f; + m_moveSpeedMultiplier = 1.0f; resetBaseParameters(parameters); } @@ -696,6 +697,10 @@ Maybe<pair<Vec2F, bool>> ActorMovementController::controlPathMove(Vec2F const& p return result; } +void ActorMovementController::setMoveSpeedMultiplier(float scale) { + m_moveSpeedMultiplier = scale; +} + void ActorMovementController::clearControls() { m_controlRotationRate = 0.0f; m_controlAcceleration = Vec2F(); @@ -951,6 +956,8 @@ void ActorMovementController::tickMaster() { : *activeParameters.walkSpeed * activeModifiers.speedModifier); } + m_targetHorizontalAmbulatingVelocity *= m_moveSpeedMultiplier; + if (m_liquidMovement.get()) m_targetHorizontalAmbulatingVelocity *= (1.0f - liquidImpedance); @@ -1102,7 +1109,7 @@ void ActorMovementController::doSetAnchorState(Maybe<EntityAnchorState> anchorSt if (m_entityAnchor) setPosition(m_entityAnchor->position); } - + PathController::PathController(World* world) : m_world(world), m_edgeTimer(0.0) { } diff --git a/source/game/StarActorMovementController.hpp b/source/game/StarActorMovementController.hpp index 11731eb..38cc6a0 100644 --- a/source/game/StarActorMovementController.hpp +++ b/source/game/StarActorMovementController.hpp @@ -239,6 +239,9 @@ public: Maybe<pair<Vec2F, bool>> pathMove(Vec2F const& pathPosition, bool run = false, Maybe<PlatformerAStar::Parameters> const& parameters = {}); Maybe<pair<Vec2F, bool>> controlPathMove(Vec2F const& pathPosition, bool run = false, Maybe<PlatformerAStar::Parameters> const& parameters = {}); + // Used for user controller input. + void setMoveSpeedMultiplier(float multiplier = 1.0f); + // Clears all control data. void clearControls(); @@ -248,6 +251,7 @@ public: void tickSlave(); + private: struct ApproachVelocityCommand { Vec2F targetVelocity; @@ -313,6 +317,7 @@ private: int m_fallThroughSustain; bool m_lastControlJump; bool m_lastControlDown; + float m_moveSpeedMultiplier; GameTimer m_reJumpTimer; Maybe<GameTimer> m_jumpHoldTimer; diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp index ccfea66..dd74503 100644 --- a/source/game/StarPlayer.cpp +++ b/source/game/StarPlayer.cpp @@ -669,6 +669,10 @@ void Player::special(int specialKey) { m_techController->special(specialKey); } +void Player::setMoveVector(Vec2F const& vec) { + m_moveVector = vec; +} + void Player::moveLeft() { m_pendingMoves.add(MoveControlType::Left); } @@ -1543,6 +1547,24 @@ void Player::disableInterpolation() { void Player::processControls() { bool run = !m_shifting && !m_statusController->statPositive("encumberance"); + + bool useMoveVector = m_moveVector.x() != 0.0f; + if (useMoveVector) { + for (auto move : m_pendingMoves) { + if (move == MoveControlType::Left || move == MoveControlType::Right) { + useMoveVector = false; + break; + } + } + } + + if (useMoveVector) { + m_pendingMoves.insert(signbit(m_moveVector.x()) ? MoveControlType::Left : MoveControlType::Right); + m_movementController->setMoveSpeedMultiplier(clamp(abs(m_moveVector.x()), 0.0f, 1.0f)); + } + else + m_movementController->setMoveSpeedMultiplier(1.0f); + if (auto fireableMain = as<FireableItem>(m_tools->primaryHandItem())) { if (fireableMain->inUse() && fireableMain->walkWhileFiring()) run = false; @@ -1621,6 +1643,7 @@ void Player::processControls() { void Player::processStateChanges() { if (isMaster()) { + // Set the current player state based on what movement controller tells us // we're doing and do some state transition logic State oldState = m_state; @@ -1662,6 +1685,9 @@ void Player::processStateChanges() { } } + if (m_moveVector.x() != 0.0f && (m_state == State::Run || m_state == State::Walk)) + m_state = abs(m_moveVector.x()) > 0.5f ? State::Run : State::Walk; + if (m_state == State::Jump && (oldState == State::Idle || oldState == State::Run || oldState == State::Walk || oldState == State::Crouch)) m_effectsAnimator->burstParticleEmitter("jump"); diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp index 1129b06..f989a77 100644 --- a/source/game/StarPlayer.hpp +++ b/source/game/StarPlayer.hpp @@ -132,6 +132,7 @@ public: void setShifting(bool shifting); void special(int specialKey); + void setMoveVector(Vec2F const& vec); void moveLeft(); void moveRight(); void moveUp(); @@ -505,6 +506,7 @@ private: Vec2F m_blinkInterval; HashSet<MoveControlType> m_pendingMoves; + Vec2F m_moveVector; bool m_shifting; ActorMovementParameters m_zeroGMovementParameters; |