From 3f93afb0ac836ef5dee389f65ef079c453943bb1 Mon Sep 17 00:00:00 2001 From: Bill Robinson Date: Thu, 19 Dec 2024 18:33:37 +0000 Subject: [PATCH] Added basic game controller support --- src/AnimatorAsset.cpp | 9 ++-- src/CMakeLists.txt | 7 +++ src/GameState.h | 1 + src/MagnumGameApp.cpp | 19 ++++++++ src/MagnumGameApp.h | 17 +++++--- src/MagnumGameApp_input.cpp | 23 +++++++++- src/MagnumGameCommon.h | 7 +++ src/Player.cpp | 7 ++- src/SdlGameController.cpp | 87 +++++++++++++++++++++++++++++++++++++ src/SdlGameController.h | 37 ++++++++++++++++ 10 files changed, 198 insertions(+), 16 deletions(-) create mode 100644 src/SdlGameController.cpp create mode 100644 src/SdlGameController.h diff --git a/src/AnimatorAsset.cpp b/src/AnimatorAsset.cpp index 2ae0e49..b807e2b 100644 --- a/src/AnimatorAsset.cpp +++ b/src/AnimatorAsset.cpp @@ -94,11 +94,10 @@ namespace MagnumGame { Debug{} << "\tMesh" << meshId << ":" << meshName; auto meshData = importer.mesh(meshId); - for (auto attrId = 0U; attrId < meshData->attributeCount(); attrId++) { - auto attrName = meshData->attributeName(attrId); - - // Debug{} << "\tAttribute" << attrId << ":" << attrName << "format=" << meshData->attributeFormat(attrId) << " offset=" << meshData->attributeOffset(attrId) << " stride=" << meshData->attributeStride(attrId) << " arraySize=" << meshData->attributeArraySize(attrId) << " morphTargetId=" << meshData->attributeMorphTargetId(attrId); - } + // for (auto attrId = 0U; attrId < meshData->attributeCount(); attrId++) { + // auto attrName = meshData->attributeName(attrId); + // Debug{} << "\tAttribute" << attrId << ":" << attrName << "format=" << meshData->attributeFormat(attrId) << " offset=" << meshData->attributeOffset(attrId) << " stride=" << meshData->attributeStride(attrId) << " arraySize=" << meshData->attributeArraySize(attrId) << " morphTargetId=" << meshData->attributeMorphTargetId(attrId); + // } [[maybe_unused]] auto &mesh = _meshes[meshId] = MeshTools::compile(*meshData); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d5bac5b..4b656c1 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -53,6 +53,13 @@ add_executable(MagnumGameApp MagnumGameApp.cpp ShadowCasterShader.h ShadowCasterShader.cpp ) +if (NOT CORRADE_TARGET_EMSCRIPTEN) + target_sources(MagnumGameApp PRIVATE + SdlGameController.cpp + SdlGameController.h + ) +endif() + target_link_libraries(MagnumGameApp PRIVATE Corrade::Main Magnum::Application diff --git a/src/GameState.h b/src/GameState.h index 8fdf024..7da0724 100644 --- a/src/GameState.h +++ b/src/GameState.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "GameAssets.h" #include "MagnumGameApp.h" diff --git a/src/MagnumGameApp.cpp b/src/MagnumGameApp.cpp index 65fd858..0eece13 100644 --- a/src/MagnumGameApp.cpp +++ b/src/MagnumGameApp.cpp @@ -35,6 +35,10 @@ #include "GameState.h" #include "UserInterface.h" +#ifdef MAGNUMGAME_SDL +#include +#include "SdlGameController.h" +#endif #ifdef BT_USE_DOUBLE_PRECISION #error sorry, this example does not support Bullet with double precision enabled @@ -125,6 +129,11 @@ namespace MagnumGame { setMinimalLoopPeriod(8.0_msec); #endif _timeline.start(); + +#ifndef CORRADE_TARGET_EMSCRIPTEN + SDL_Init(SDL_INIT_GAMECONTROLLER); + _gameController.emplace(_gameState); +#endif } bool MagnumGameApp::isPlaying() { @@ -148,6 +157,14 @@ namespace MagnumGame { .bind(); if (isPlaying()) { + +#ifdef MAGNUMGAME_SDL + auto cameraControl = _gameController->getCameraDirectionalControlVector(); + if (!cameraControl.isZero()) { + _gameState->getCamera()->rotateBy(cameraControl.x() * 90.0_degf * _timeline.previousFrameDuration(), cameraControl.y() * -90.0_degf * _timeline.previousFrameDuration()); + } +#endif + _gameState->setControl(getPlayerControlVector()); _gameState->update(); updateStatusText(); @@ -207,6 +224,8 @@ namespace MagnumGame { CHECK_GL_ERROR(); } + + } MAGNUM_APPLICATION_MAIN(MagnumGame::MagnumGameApp) diff --git a/src/MagnumGameApp.h b/src/MagnumGameApp.h index 10f09ff..4c3f1e6 100644 --- a/src/MagnumGameApp.h +++ b/src/MagnumGameApp.h @@ -1,5 +1,4 @@ #pragma once -#include #ifndef CORRADE_TARGET_EMSCRIPTEN #include @@ -7,22 +6,20 @@ #include #endif -#include -#include +#include +#include #include #include -#include #include #include #include -#include #include -#include #include "Animator.h" #include "RigidBody.h" #include "CameraController.h" #include "DebugLines.h" +#include "MagnumGameCommon.h" namespace MagnumGame { class UIText; @@ -34,6 +31,7 @@ namespace MagnumGame { class GameAssets; class Animator; struct AnimatorAsset; + class SdlGameController; class MagnumGameApp : public Platform::Application { public: @@ -64,8 +62,9 @@ namespace MagnumGame { void pointerMoveEvent(PointerMoveEvent &event) override; void scrollEvent(ScrollEvent &event) override; -#ifdef MAGNUM_SDL2APPLICATION_MAIN +#ifdef MAGNUMGAME_SDL void anyEvent(SDL_Event &event) override; + #endif @@ -96,6 +95,10 @@ namespace MagnumGame { Containers::Pointer _debugLines; Containers::Pointer _tweakables; +#ifdef MAGNUMGAME_SDL + Containers::Pointer _gameController; +#endif + int _controllerKeysHeld; std::unordered_map _pointerPressLocations{}; diff --git a/src/MagnumGameApp_input.cpp b/src/MagnumGameApp_input.cpp index 65dc606..dfb3ad2 100644 --- a/src/MagnumGameApp_input.cpp +++ b/src/MagnumGameApp_input.cpp @@ -4,8 +4,9 @@ #include #include #include -#ifdef MAGNUM_SDL2APPLICATION_MAIN +#ifdef MAGNUMGAME_SDL #include +#include "SdlGameController.h" #endif #include "GameState.h" @@ -38,10 +39,21 @@ namespace MagnumGame { Vector2 MagnumGameApp::getPlayerControlVector() const { - return { + Vector2 control{ ((_controllerKeysHeld&KEY_RIGHT)?1.0f:0.0f) - ((_controllerKeysHeld&KEY_LEFT)?1.0f:0.0f), ((_controllerKeysHeld&KEY_FORWARD)?1.0f:0.0f) - ((_controllerKeysHeld&KEY_BACKWARD)?1.0f:0.0f), }; + +#ifdef MAGNUMGAME_SDL + if (_gameController) { + auto gameControllerVector = _gameController->getPlayerDirectionalControlVector(); + if (!gameControllerVector.isZero()) { + control = gameControllerVector; + } + } +#endif + + return control; } @@ -166,7 +178,14 @@ namespace MagnumGame { void MagnumGameApp::anyEvent(SDL_Event &event) { if (event.type == SDL_WINDOWEVENT_FOCUS_LOST) { _controllerKeysHeld = 0; + return ; + } + if (_gameController) { + if (_gameController->handleEvent(event)) { + return; + } } + Debug{} << "Unhandled SDL event" << event.type; } #endif } diff --git a/src/MagnumGameCommon.h b/src/MagnumGameCommon.h index 9486beb..11943ad 100644 --- a/src/MagnumGameCommon.h +++ b/src/MagnumGameCommon.h @@ -2,6 +2,13 @@ #include #include + +#ifndef CORRADE_TARGET_EMSCRIPTEN +#define MAGNUMGAME_SDL +#else +#define MAGNUMGAME_EMSCRIPTEN +#endif + using namespace Magnum; using namespace Magnum::Math::Literals; diff --git a/src/Player.cpp b/src/Player.cpp index cf837de..4e012a2 100644 --- a/src/Player.cpp +++ b/src/Player.cpp @@ -2,7 +2,7 @@ // Created by Bill Robinson on 15/07/2024. // -#include +#include #include "Player.h" #include "OnGroundQuery.h" @@ -73,7 +73,10 @@ namespace MagnumGame { if (!controlVector.isZero()) { cameraControlVector = cameraObjectMatrix.transformVector({ controlVector.x(), 0, -controlVector.y() }); cameraControlVector.y() = 0; - cameraControlVector = cameraControlVector.normalized(); + auto vectorLength = cameraControlVector.length(); + if (vectorLength > 1) { + cameraControlVector /= vectorLength; + } } else { cameraControlVector = {}; diff --git a/src/SdlGameController.cpp b/src/SdlGameController.cpp new file mode 100644 index 0000000..860ad1e --- /dev/null +++ b/src/SdlGameController.cpp @@ -0,0 +1,87 @@ +// +// Created by Bill Robinson on 19/12/2024. +// + +#include "SdlGameController.h" +#include "GameState.h" +#include "Player.h" + +namespace MagnumGame { + static SDL_GameController *findController() { + for (int i = 0; i < SDL_NumJoysticks(); i++) { + if (SDL_IsGameController(i)) { + return SDL_GameControllerOpen(i); + } + } + + return nullptr; + } + + SdlGameController::SdlGameController(Containers::Pointer &gameState) + : _controller(findController()), + _gameState(gameState) { + } + + SdlGameController::~SdlGameController() { + if (_controller) { + SDL_GameControllerClose(_controller); + } + } + + Vector2 SdlGameController::readAxisVector(::SDL_GameControllerAxis xAxis, ::SDL_GameControllerAxis yAxis) const { + Vector2 input{ + static_cast(SDL_GameControllerGetAxis(_controller, xAxis)) / (1 << 15), + static_cast(SDL_GameControllerGetAxis(_controller, yAxis)) / (1 << 15) + }; + + if (abs(input.x()) < JoystickDeadzone) { + input.x() = 0; + } + if (abs(input.y()) < JoystickDeadzone) { + input.y() = 0; + } + return input; + } + + Vector2 SdlGameController::getPlayerDirectionalControlVector() const { + if (_controller) { + auto vector = readAxisVector(SDL_CONTROLLER_AXIS_LEFTX, SDL_CONTROLLER_AXIS_LEFTY); + vector.y() = -vector.y(); + return vector; + } + return {0, 0}; + } + + Vector2 SdlGameController::getCameraDirectionalControlVector() const { + if (_controller) { + return readAxisVector(SDL_CONTROLLER_AXIS_RIGHTX, SDL_CONTROLLER_AXIS_RIGHTY); + } + return {0, 0}; + } + + + bool SdlGameController::handleEvent(const SDL_Event &event) { + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + if (!_controller) { + _controller = SDL_GameControllerOpen(event.cdevice.which); + return true; + } + break; + case SDL_CONTROLLERDEVICEREMOVED: + if (_controller && event.cdevice.which == SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(_controller))) { + SDL_GameControllerClose(_controller); + _controller = findController(); + return true; + } + break; + case SDL_CONTROLLERBUTTONDOWN: + if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A) { + _gameState->getPlayer()->tryJump(); + return true; + } + break; + } + return false; + } +} diff --git a/src/SdlGameController.h b/src/SdlGameController.h new file mode 100644 index 0000000..c821b49 --- /dev/null +++ b/src/SdlGameController.h @@ -0,0 +1,37 @@ +#pragma once + +#include + +#include "MagnumGameCommon.h" +#include +#include + +namespace MagnumGame { + + class GameState; + + + class SdlGameController { + public: + explicit SdlGameController(Containers::Pointer& gameState); + ~SdlGameController(); + + Vector2 readAxisVector(SDL_GameControllerAxis xAxis, SDL_GameControllerAxis yAxis) const; + + Vector2 getPlayerDirectionalControlVector() const; + + Vector2 getCameraDirectionalControlVector() const; + + bool handleEvent(const SDL_Event &event); + + static inline float JoystickDeadzone = 0.05f; + + private: + SDL_GameController* _controller; + Containers::Pointer& _gameState; + }; + +} + + +