From 6a5b74b3e6599ab04db63efb6070904d732ef928 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Fri, 9 Feb 2024 23:41:39 -0600 Subject: [PATCH] Added in shoulder button navigation schemes, related icons, and DAS press input handling for menu navigation. Added in button visibility settings for input helper. Added Confirm input display for load game window. --- .../AdventuresInLestoria.cpp | 26 +++++++++++------- Adventures in Lestoria/AdventuresInLestoria.h | 3 ++ Adventures in Lestoria/InputHelper.cpp | 4 ++- Adventures in Lestoria/Key.cpp | 10 +++++-- Adventures in Lestoria/Key.h | 7 ++++- Adventures in Lestoria/LoadGameWindow.cpp | 10 +++++++ Adventures in Lestoria/MainMenuWindow.cpp | 2 +- Adventures in Lestoria/Menu.cpp | 3 ++ .../ScrollableWindowComponent.h | 7 ++++- Adventures in Lestoria/Version.h | 2 +- .../assets/config/gfx/gfx.txt | 3 ++ .../assets/themes/button_qe.png | Bin 0 -> 7406 bytes .../assets/themes/button_r1l1.png | Bin 0 -> 7907 bytes Adventures in Lestoria/olcPGEX_Gamepad.h | 5 +++- Adventures in Lestoria/olcPixelGameEngine.h | 5 +++- 15 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 Adventures in Lestoria/assets/themes/button_qe.png create mode 100644 Adventures in Lestoria/assets/themes/button_r1l1.png diff --git a/Adventures in Lestoria/AdventuresInLestoria.cpp b/Adventures in Lestoria/AdventuresInLestoria.cpp index 8f3675c9..3493afbc 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.cpp +++ b/Adventures in Lestoria/AdventuresInLestoria.cpp @@ -115,11 +115,14 @@ InputGroup AiL::KEY_UNEQUIP; InputGroup AiL::KEY_SCROLLDOWN; InputGroup AiL::KEY_SCROLLUP; +InputGroup AiL::KEY_FASTSCROLLDOWN; +InputGroup AiL::KEY_FASTSCROLLUP; InputGroup AiL::KEY_SCROLLLEFT; InputGroup AiL::KEY_SCROLLRIGHT; InputGroup AiL::KEY_SCROLLHORZ; InputGroup AiL::KEY_SCROLLVERT; InputGroup AiL::KEY_SCROLL; +InputGroup AiL::KEY_SHOULDER; InputGroup AiL::KEY_CHANGE_LOADOUT; #ifndef __EMSCRIPTEN__ @@ -2490,16 +2493,16 @@ void AiL::InitializeDefaultKeybinds(){ KEY_MENU.AddKeybind({KEY,ESCAPE}); KEY_MENU.AddKeybind({CONTROLLER,static_cast(GPButtons::START)}); - KEY_SCROLLUP.AddKeybind({KEY,Q}); - KEY_SCROLLUP.AddKeybind({KEY,PGUP}); - KEY_SCROLLUP.AddKeybind({KEY,NP8}); - KEY_SCROLLUP.AddKeybind({CONTROLLER,static_cast(GPButtons::L1)}); - KEY_SCROLLUP.AddKeybind({CONTROLLER,static_cast(GPButtons::L2)}); - KEY_SCROLLDOWN.AddKeybind({KEY,E}); - KEY_SCROLLDOWN.AddKeybind({KEY,PGDN}); - KEY_SCROLLDOWN.AddKeybind({KEY,NP2}); - KEY_SCROLLDOWN.AddKeybind({CONTROLLER,static_cast(GPButtons::R1)}); - KEY_SCROLLDOWN.AddKeybind({CONTROLLER,static_cast(GPButtons::R2)}); + KEY_FASTSCROLLUP.AddKeybind({KEY,Q}); + KEY_FASTSCROLLUP.AddKeybind({KEY,PGUP}); + KEY_FASTSCROLLUP.AddKeybind({KEY,NP8}); + KEY_FASTSCROLLUP.AddKeybind({CONTROLLER,static_cast(GPButtons::L1)}); + KEY_FASTSCROLLUP.AddKeybind({CONTROLLER,static_cast(GPButtons::L2)}); + KEY_FASTSCROLLDOWN.AddKeybind({KEY,E}); + KEY_FASTSCROLLDOWN.AddKeybind({KEY,PGDN}); + KEY_FASTSCROLLDOWN.AddKeybind({KEY,NP2}); + KEY_FASTSCROLLDOWN.AddKeybind({CONTROLLER,static_cast(GPButtons::R1)}); + KEY_FASTSCROLLDOWN.AddKeybind({CONTROLLER,static_cast(GPButtons::R2)}); KEY_CHANGE_LOADOUT.AddKeybind({KEY,X}); KEY_CHANGE_LOADOUT.AddKeybind({CONTROLLER,static_cast(GPButtons::FACE_U)}); @@ -2523,6 +2526,9 @@ void AiL::InitializeDefaultKeybinds(){ KEY_SCROLLHORZ.AddKeybind({ANALOG,static_cast(GPAxes::RX)}); KEY_SCROLL.AddKeybind({ANALOG,static_cast(GPAxes::ALL)}); + KEY_SHOULDER.AddKeybind({KEY,SHOULDER}); + KEY_SHOULDER.AddKeybind({CONTROLLER,static_cast(GPButtons::SHOULDER)}); + KEY_UNEQUIP.AddKeybind({KEY,R}); KEY_UNEQUIP.AddKeybind({CONTROLLER,static_cast(GPButtons::FACE_U)}); diff --git a/Adventures in Lestoria/AdventuresInLestoria.h b/Adventures in Lestoria/AdventuresInLestoria.h index 52482b79..35094b1b 100644 --- a/Adventures in Lestoria/AdventuresInLestoria.h +++ b/Adventures in Lestoria/AdventuresInLestoria.h @@ -86,6 +86,8 @@ public: static InputGroup KEY_START; static InputGroup KEY_SELECT; + static InputGroup KEY_FASTSCROLLDOWN; + static InputGroup KEY_FASTSCROLLUP; static InputGroup KEY_SCROLLDOWN; static InputGroup KEY_SCROLLUP; static InputGroup KEY_SCROLLLEFT; @@ -93,6 +95,7 @@ public: static InputGroup KEY_SCROLLHORZ; static InputGroup KEY_SCROLLVERT; static InputGroup KEY_SCROLL; + static InputGroup KEY_SHOULDER; static InputGroup KEY_CHANGE_LOADOUT; static float SIZE_CHANGE_SPEED; diff --git a/Adventures in Lestoria/InputHelper.cpp b/Adventures in Lestoria/InputHelper.cpp index c9845980..779e2fbd 100644 --- a/Adventures in Lestoria/InputHelper.cpp +++ b/Adventures in Lestoria/InputHelper.cpp @@ -47,7 +47,9 @@ InputHelper::InputHelper(){} void InputHelper::Initialize(MenuInputGroups&inputGroups){ for(auto&data:inputGroups){ - this->inputGroups[data.first.GetGroup()]=data.second.first; + if(data.first.GetLabelVisible()){ //If the label is not visible, we don't care to include it in our list. + this->inputGroups[data.first.GetGroup()]=data.second.first; + } } } diff --git a/Adventures in Lestoria/Key.cpp b/Adventures in Lestoria/Key.cpp index 11600ce8..02ce1a89 100644 --- a/Adventures in Lestoria/Key.cpp +++ b/Adventures in Lestoria/Key.cpp @@ -481,6 +481,7 @@ std::map,GenericKey::KeyInfo> GenericKey::keyLiteral={ {{KEY, OEM_8},{"\\"}}, {{KEY, CAPS_LOCK},{"CAP LK"}}, {{KEY, olc::ENUM_END},{""}}, + {{KEY, SHOULDER},{"Q-E","themes/button_qe.png"}}, {{MOUSE, Mouse::LEFT},{"L.MOUSE"}}, {{MOUSE, Mouse::RIGHT},{"R.MOUSE"}}, {{MOUSE, Mouse::MIDDLE},{"M.MOUSE"}}, @@ -500,6 +501,7 @@ std::map,GenericKey::KeyInfo> GenericKey::keyLiteral={ {{CONTROLLER, static_cast(GPButtons::DPAD_R)},{"RIGHT"}}, {{CONTROLLER, static_cast(GPButtons::DPAD_U)},{"UP"}}, {{CONTROLLER, static_cast(GPButtons::DPAD_D)},{"DOWN"}}, + {{CONTROLLER, static_cast(GPButtons::SHOULDER)},{"L1-R1","themes/button_r1l1.png"}}, {{ANALOG, static_cast(GPAxes::LY)},{"Up/Down","themes/button_analogstick_vert.png"}}, {{ANALOG, static_cast(GPAxes::RY)},{"Up/Down","themes/button_analogstick_vert.png"}}, {{ANALOG, static_cast(GPAxes::LX)},{"Right/Left","themes/button_analogstick_horz.png"}}, @@ -589,8 +591,8 @@ const bool operator==(const Input&input1,const Input&input2){ return input1.type==input2.type&&input1.key==input2.key; } -InputEngageGroup::InputEngageGroup(InputGroup&group,EngageType type) - :group(group),type(type){} +InputEngageGroup::InputEngageGroup(InputGroup&group,EngageType type,const bool labelVisible) + :group(group),type(type),labelVisible(labelVisible){} const InputEngageGroup::EngageType InputEngageGroup::GetEngageType()const{ @@ -653,4 +655,8 @@ void InputListener::Update(){ const int Input::GetKeyCode()const{ return key; +} + +const bool InputEngageGroup::GetLabelVisible()const{ + return labelVisible; } \ No newline at end of file diff --git a/Adventures in Lestoria/Key.h b/Adventures in Lestoria/Key.h index 09b88d95..6a31d86f 100644 --- a/Adventures in Lestoria/Key.h +++ b/Adventures in Lestoria/Key.h @@ -121,8 +121,11 @@ public: class InputEngageGroup{ public: + static const bool VISIBLE=true; + static const bool NOT_VISIBLE=false; enum EngageType{ Pressed, + PressedDAS, Held, Released, Analog, @@ -130,11 +133,13 @@ public: private: InputGroup&group; EngageType type; + bool labelVisible; public: - InputEngageGroup(InputGroup&group,EngageType type=Released); + InputEngageGroup(InputGroup&group,EngageType type=Released,const bool labelVisible=true); const EngageType GetEngageType()const; InputGroup&GetGroup()const; const InputEngageGroup operator=(const InputEngageGroup&rhs); + const bool GetLabelVisible()const; }; class GenericKey{ diff --git a/Adventures in Lestoria/LoadGameWindow.cpp b/Adventures in Lestoria/LoadGameWindow.cpp index 0e1ee4e6..42a474f1 100644 --- a/Adventures in Lestoria/LoadGameWindow.cpp +++ b/Adventures in Lestoria/LoadGameWindow.cpp @@ -98,7 +98,17 @@ void Menu::InitializeLoadGameWindow(){ {{game->KEY_BACK},{"Back to Title Screen",[](MenuType type){ Component(type,"Go Back Button")->Click(); }}}, + {{game->KEY_CONFIRM},{"Load",[](MenuType type){}}}, {{game->KEY_SCROLLVERT,Analog},{"Scroll",[](MenuType type){}}}, + {{game->KEY_SHOULDER,Pressed},{"Scroll",[](MenuType type){}}}, + {{game->KEY_FASTSCROLLDOWN,PressedDAS,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){ + auto gameFilesList=Component(type,"Game Files List"); + gameFilesList->IncreaseSelectionIndex(3.f); + }}}, + {{game->KEY_FASTSCROLLUP,PressedDAS,InputEngageGroup::NOT_VISIBLE},{"Scroll",[](MenuType type){ + auto gameFilesList=Component(type,"Game Files List"); + gameFilesList->IncreaseSelectionIndex(-3.f); + }}}, } ,{ //Button Navigation Rules {"Game Files List",{ diff --git a/Adventures in Lestoria/MainMenuWindow.cpp b/Adventures in Lestoria/MainMenuWindow.cpp index 186fbf63..f090a93e 100644 --- a/Adventures in Lestoria/MainMenuWindow.cpp +++ b/Adventures in Lestoria/MainMenuWindow.cpp @@ -74,8 +74,8 @@ void Menu::InitializeMainMenuWindow(){ } }, { //Button Key - {game->KEY_CONFIRM,{"Select",[](MenuType type){}}}, {game->KEY_BACK,{"Back",[](MenuType type){}}}, + {game->KEY_CONFIRM,{"Select",[](MenuType type){}}}, } ,{ //Button Navigation Rules {"New Game Button",{ diff --git a/Adventures in Lestoria/Menu.cpp b/Adventures in Lestoria/Menu.cpp index 483addb1..20b0b494 100644 --- a/Adventures in Lestoria/Menu.cpp +++ b/Adventures in Lestoria/Menu.cpp @@ -312,6 +312,9 @@ void Menu::KeyboardButtonNavigation(AiL*game,vf2d menuPos){ case Pressed:{ activated=input.GetGroup().Pressed(); }break; + case PressedDAS:{ + activated=input.GetGroup().PressedDAS(); + }break; case Held:{ activated=input.GetGroup().Held(); }break; diff --git a/Adventures in Lestoria/ScrollableWindowComponent.h b/Adventures in Lestoria/ScrollableWindowComponent.h index 90aad62e..b180b77c 100644 --- a/Adventures in Lestoria/ScrollableWindowComponent.h +++ b/Adventures in Lestoria/ScrollableWindowComponent.h @@ -59,7 +59,6 @@ protected: vf2d targetScrollOffset{}; float lastScrollUpdate=0.f; float selectionIndex=0.f; - int selectionSkipIncrement=1; //How many items are on each row. This determines the increments that we skip by while scrolling. protected: inline bool OnScreen(std::weak_ptrcomponent){ return geom2d::overlaps(geom2d::rect{{},rect.size},geom2d::rect{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}}); @@ -105,6 +104,12 @@ public: return geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos,rect.size},game->GetMousePos())&& //Make sure the mouse is inside the parent window component first.... geom2d::overlaps(geom2d::rect{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos()); } + + inline void IncreaseSelectionIndex(const float val){ + float prevIndex=selectionIndex; + selectionIndex=std::clamp(selectionIndex+val,0.f,float(components.size()-1)); + if(size_t(prevIndex)!=size_t(selectionIndex)){Menu::menus[parentMenu]->SetSelection(components[size_t(selectionIndex)],false);} + } protected: virtual inline vf2d GetScrollAmount()const{ return scrollOffset; diff --git a/Adventures in Lestoria/Version.h b/Adventures in Lestoria/Version.h index 164fc87f..65dca823 100644 --- a/Adventures in Lestoria/Version.h +++ b/Adventures in Lestoria/Version.h @@ -39,7 +39,7 @@ All rights reserved. #define VERSION_MAJOR 0 #define VERSION_MINOR 3 #define VERSION_PATCH 0 -#define VERSION_BUILD 6933 +#define VERSION_BUILD 6936 #define stringify(a) stringify_(a) #define stringify_(a) #a diff --git a/Adventures in Lestoria/assets/config/gfx/gfx.txt b/Adventures in Lestoria/assets/config/gfx/gfx.txt index a6ea0389..e8a7b797 100644 --- a/Adventures in Lestoria/assets/config/gfx/gfx.txt +++ b/Adventures in Lestoria/assets/config/gfx/gfx.txt @@ -60,6 +60,9 @@ Images GFX_Button_Face_L2 = themes/button_l2.png GFX_Button_Face_R1 = themes/button_r1.png GFX_Button_Face_R2 = themes/button_r2.png + GFX_Button_SHOULDER_QE = themes/button_qe.png + GFX_Button_SHOULDER_L1R1 = themes/button_r1l1.png + GFX_Button_AnalogStick = themes/button_analogstick.png GFX_Overworld_Arrow = overworld_arrow.png GFX_Exclamation = exclamation.png GFX_Ursule2 = monsters/Ursule Mother of Bears2.png diff --git a/Adventures in Lestoria/assets/themes/button_qe.png b/Adventures in Lestoria/assets/themes/button_qe.png new file mode 100644 index 0000000000000000000000000000000000000000..b66bc18c97d3a7a23cd15d59f85968d1ad79ba71 GIT binary patch literal 7406 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 K5=wMV2mc3M_4f<_ literal 0 HcmV?d00001 diff --git a/Adventures in Lestoria/assets/themes/button_r1l1.png b/Adventures in Lestoria/assets/themes/button_r1l1.png new file mode 100644 index 0000000000000000000000000000000000000000..4ad729fbe3709460ada45b7f9d45d85d5942e67e GIT binary patch literal 7907 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