diff --git a/src/gamebase.cpp b/src/gamebase.cpp index 0fd9b20..04a5ca1 100644 --- a/src/gamebase.cpp +++ b/src/gamebase.cpp @@ -1,18 +1,30 @@ #include "gamebase.hpp" #include "texture.hpp" #include "sdlmain.hpp" +#include "inputbag.hpp" +#include "key.hpp" #include #include #include +#include namespace cloonel { namespace { ///--------------------------------------------------------------------- ///--------------------------------------------------------------------- - bool DoEvents() { + bool DoEvents (InputBag& parInput) { SDL_Event eve; while (SDL_PollEvent(&eve)) { switch (eve.type) { + case SDL_KEYDOWN: + //eve.key.keysym.sym + parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, true); + break; + + case SDL_KEYUP: + parInput.NotifyKeyAction(InputDevice_Keyboard, eve.key.keysym.scancode, false); + break; + case SDL_QUIT: return true; } @@ -24,6 +36,7 @@ namespace cloonel { ///------------------------------------------------------------------------ ///------------------------------------------------------------------------ GameBase::GameBase (SDLMain* parSdlMain) : + m_input(new InputBag()), m_sdlmain(parSdlMain), m_time0(SDL_GetTicks()), m_wantsToQuit(false) @@ -49,7 +62,8 @@ namespace cloonel { OnRender(); SDL_RenderPresent(ren); - m_wantsToQuit = DoEvents(); + m_wantsToQuit = DoEvents(*m_input); + m_input->KeyStateUpdateFinished(); return delta; } diff --git a/src/gamebase.hpp b/src/gamebase.hpp index 08c9193..d9f3089 100644 --- a/src/gamebase.hpp +++ b/src/gamebase.hpp @@ -6,6 +6,7 @@ namespace cloonel { class SDLMain; class Texture; + class InputBag; class GameBase { public: @@ -20,12 +21,14 @@ namespace cloonel { virtual void Destroy ( void ) noexcept = 0; SDLMain* SDLObject ( void ) { return m_sdlmain; } + InputBag* InputBagObject ( void ) { return m_input.get(); } private: virtual void OnRender ( void ) = 0; virtual void OnUpdate ( float parDelta ) = 0; virtual bool ShouldQuit ( void ) const; + const std::unique_ptr m_input; SDLMain* const m_sdlmain; unsigned int m_time0; bool m_wantsToQuit; diff --git a/src/gameplaysceneclassic.cpp b/src/gameplaysceneclassic.cpp index 7c45008..8685d9f 100644 --- a/src/gameplaysceneclassic.cpp +++ b/src/gameplaysceneclassic.cpp @@ -2,9 +2,19 @@ #include "character.hpp" #include "moversine.hpp" #include "sdlmain.hpp" +#include "inputbag.hpp" +#include "key.hpp" #include +#include namespace cloonel { + namespace { + enum GameActionType { + GameAction_Left, + GameAction_Right + }; + } //unnamed namespace + struct GameplaySceneClassic::LocalData { }; @@ -14,6 +24,10 @@ namespace cloonel { GameplayScene(parSdlMain), m_local(new LocalData) { + //TODO: replace the hardcoded bindings with something more customizable. + InputBag& input = *InputBagObject(); + input.AddAction(GameAction_Left, Key(InputDevice_Keyboard, SDL_SCANCODE_LEFT), "Move left"); + input.AddAction(GameAction_Left, Key(InputDevice_Keyboard, SDL_SCANCODE_RIGHT), "Move right"); } ///-------------------------------------------------------------------------- diff --git a/src/inputbag.cpp b/src/inputbag.cpp index e1cc74f..d8364b0 100644 --- a/src/inputbag.cpp +++ b/src/inputbag.cpp @@ -3,12 +3,17 @@ #include #include #include +#include +#include namespace cloonel { struct Action { Key key; const std::string name; InputBag::ActionStateType state; + bool newStatePressed; + + bool operator== ( const Key& parKey ) const { return key == parKey; } }; struct InputBag::LocalData { @@ -17,6 +22,23 @@ namespace cloonel { }; namespace { + // | rl | pr + // ----------------- + // rel | rel | jpr + // prs | jrl | prs + // jrl | rel | jpr + // jpr | jrl | prs + const InputBag::ActionStateType g_stateTruthTable[] = { + InputBag::ActionState_Released, + InputBag::ActionState_JustReleased, + InputBag::ActionState_Released, + InputBag::ActionState_JustReleased, + InputBag::ActionState_JustPressed, + InputBag::ActionState_Pressed, + InputBag::ActionState_JustPressed, + InputBag::ActionState_Pressed + }; + ///---------------------------------------------------------------------- ///When actions vector is reallocated, update pointers in mappings. ///---------------------------------------------------------------------- @@ -45,7 +67,7 @@ namespace cloonel { ///-------------------------------------------------------------------------- void InputBag::AddAction (int parAction, const Key& parKey, std::string&& parName) { Action* const oldBuff = m_localdata->actions.data(); - m_localdata->actions.push_back(Action({parKey, parName, ActionState_Released})); + m_localdata->actions.push_back(Action({parKey, parName, ActionState_Released, false})); Action* const newBuff = m_localdata->actions.data(); if (oldBuff != newBuff) { UpdatePointers(oldBuff, newBuff, m_localdata->mappings, 0); @@ -66,4 +88,37 @@ namespace cloonel { m_localdata->actions.clear(); m_localdata->mappings.clear(); } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::NotifyKeyAction (InputDeviceType parDev, int parScancode, bool parPressed) { + const Key searchKey(parDev, parScancode); + auto itFound = std::find(m_localdata->actions.begin(), m_localdata->actions.end(), searchKey); + //This method gets called every time a keypress or keyrelease is + //produced, but if the key is of any use is decided here. So it possible + //that a keystroke is not bound to any action and therefore no + //corresponding element is present in the actions list. + if (m_localdata->actions.end() != itFound) + itFound->newStatePressed = parPressed; + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::KeyStateUpdateFinished() noexcept { + for (auto& currAction : m_localdata->actions) { + const int numericState = static_cast(currAction.state); + assert(numericState < 4); + const int index = (currAction.newStatePressed ? 4 : 0) + numericState; + currAction.state = g_stateTruthTable[index]; + } + } + + ///-------------------------------------------------------------------------- + ///-------------------------------------------------------------------------- + void InputBag::ClearState() { + for (auto& currAction : m_localdata->actions) { + currAction.newStatePressed = false; + currAction.state = ActionState_Released; + } + } } //namespace cloonel diff --git a/src/inputbag.hpp b/src/inputbag.hpp index f1dbed4..2dfa84d 100644 --- a/src/inputbag.hpp +++ b/src/inputbag.hpp @@ -1,6 +1,7 @@ #ifndef idF4E67FC292A5480DA4305B806170F520 #define idF4E67FC292A5480DA4305B806170F520 +#include "inputdevicetype.hpp" #include namespace cloonel { @@ -21,6 +22,9 @@ namespace cloonel { void AddAction ( int parAction, const Key& parKey, std::string&& parName ); ActionStateType ActionState ( int parAction ) const; void Clear ( void ); + void NotifyKeyAction ( InputDeviceType parDev, int parScancode, bool parPressed ); + void KeyStateUpdateFinished ( void ) noexcept; + void ClearState ( void ); private: struct LocalData; diff --git a/src/inputdevicetype.hpp b/src/inputdevicetype.hpp new file mode 100644 index 0000000..0340d9f --- /dev/null +++ b/src/inputdevicetype.hpp @@ -0,0 +1,10 @@ +#ifndef idED0C5C9767B64910A2998ACDAE14A509 +#define idED0C5C9767B64910A2998ACDAE14A509 + +namespace cloonel { + enum InputDeviceType { + InputDevice_Keyboard + }; +} //namespace cloonel + +#endif diff --git a/src/key.hpp b/src/key.hpp index 0124df7..985b87d 100644 --- a/src/key.hpp +++ b/src/key.hpp @@ -1,16 +1,13 @@ #ifndef id8F6145D6CFBA40338C5804DEC032CE16 #define id8F6145D6CFBA40338C5804DEC032CE16 +#include "inputdevicetype.hpp" #include namespace cloonel { struct Key { - enum KeyDevice { - KeyDevice_Keyboard - }; - Key ( void ) = default; - Key ( KeyDevice parDev, int parScancode, const char parLabel[4] ) : + Key ( InputDeviceType parDev, int parScancode, const char parLabel[4] ) : srcdevice(parDev), scancode(parScancode) { @@ -19,6 +16,12 @@ namespace cloonel { label[2] = parLabel[2]; label[3] = parLabel[3]; } + Key ( InputDeviceType parDev, int parScancode ) : + srcdevice(parDev), + scancode(parScancode), + label {0, 0, 0, 0} + { + } ~Key ( void ) noexcept = default; bool operator== ( const Key& parOther ) const { @@ -31,7 +34,7 @@ namespace cloonel { return (srcdevice == parOther.srcdevice and scancode < parOther.scancode) or (srcdevice < parOther.srcdevice); } - KeyDevice srcdevice; + InputDeviceType srcdevice; int scancode; char label[4]; };