Auto targeting a component when navigating/selecting in a ScrollableWindowComponent using gamepad/keyboard controls. Added analog stick navigation to load file menu.

pull/35/head
sigonasr2 1 year ago
parent df08aa9936
commit df10dc43a8
  1. 1
      Adventures in Lestoria/Adventures in Lestoria.vcxproj
  2. 3
      Adventures in Lestoria/Adventures in Lestoria.vcxproj.filters
  3. 22
      Adventures in Lestoria/Key.cpp
  4. 1
      Adventures in Lestoria/Key.h
  5. 9
      Adventures in Lestoria/LoadGameWindow.cpp
  6. 12
      Adventures in Lestoria/Menu.cpp
  7. 2
      Adventures in Lestoria/MenuComponent.h
  8. 28
      Adventures in Lestoria/ScrollableWindowComponent.h
  9. 7
      Adventures in Lestoria/TODO.txt
  10. 6
      Adventures in Lestoria/Version.h
  11. 2
      Adventures in Lestoria/assets/config/Interface.txt

@ -695,6 +695,7 @@
<Text Include="assets\config\gfx\backdrops.txt" /> <Text Include="assets\config\gfx\backdrops.txt" />
<Text Include="assets\config\gfx\gfx.txt" /> <Text Include="assets\config\gfx\gfx.txt" />
<Text Include="assets\config\gfx\themes.txt" /> <Text Include="assets\config\gfx\themes.txt" />
<Text Include="assets\config\Interface.txt" />
<Text Include="assets\config\items\Accessories.txt" /> <Text Include="assets\config\items\Accessories.txt" />
<Text Include="assets\config\items\Equipment.txt" /> <Text Include="assets\config\items\Equipment.txt" />
<Text Include="assets\config\items\ItemCategory.txt" /> <Text Include="assets\config\items\ItemCategory.txt" />

@ -864,6 +864,9 @@
<Text Include="Chapter_1_2nd_Boss.txt"> <Text Include="Chapter_1_2nd_Boss.txt">
<Filter>Documentation\Mechanics</Filter> <Filter>Documentation\Mechanics</Filter>
</Text> </Text>
<Text Include="assets\config\Interface.txt">
<Filter>Configurations</Filter>
</Text>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Image Include="assets\heart.ico"> <Image Include="assets\heart.ico">

@ -62,6 +62,9 @@ bool Input::Pressed(){
if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bPressed)inputPressed=true; if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bPressed)inputPressed=true;
} }
}break; }break;
case ANALOG:{
//An analog input can never be "pressed". No-op.
}break;
default:{ default:{
ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type); ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type);
} }
@ -88,6 +91,9 @@ bool Input::Held(){
if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bHeld)inputHeld=true; if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bHeld)inputHeld=true;
} }
}break; }break;
case ANALOG:{
//An analog input can never be "held". No-op.
}break;
default:{ default:{
ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type); ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type);
} }
@ -114,6 +120,9 @@ bool Input::Released(){
if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bReleased)inputReleased=true; if(gamepad->stillConnected&&gamepad->getButton(static_cast<GPButtons>(key)).bReleased)inputReleased=true;
} }
}break; }break;
case ANALOG:{
//An analog input can never be "released". No-op.
}break;
default:{ default:{
ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type); ERR("Invalid Control Scheme detected! We shouldn't be here!! Type is "<<type);
} }
@ -139,6 +148,11 @@ float Input::Analog(){
} }
} }
}break; }break;
case KEY:
case MOUSE:
case CONTROLLER:{
//Doesn't return analog inputs. No-op.
}break;
default:{ default:{
ERR("Invalid Control Scheme detected for analog controls! We shouldn't be here!! Type is "<<type); ERR("Invalid Control Scheme detected for analog controls! We shouldn't be here!! Type is "<<type);
} }
@ -181,6 +195,14 @@ const bool InputGroup::Released()const{
return false; return false;
} }
const float InputGroup::Analog()const{
for(Input input:keys){
float analogVal=input.Analog();
if(analogVal!=0.f)return analogVal;
}
return 0.f;
}
std::string InputGroup::GetDisplayName(){ std::string InputGroup::GetDisplayName(){
std::string combinationDisplay=""; std::string combinationDisplay="";
for(Input input:keys){ for(Input input:keys){

@ -80,6 +80,7 @@ public:
const bool Pressed()const; const bool Pressed()const;
const bool Held()const; const bool Held()const;
const bool Released()const; const bool Released()const;
const float Analog()const;
std::string GetDisplayName(); std::string GetDisplayName();
}; };

@ -60,8 +60,13 @@ void Menu::InitializeLoadGameWindow(){
Component<MenuComponent>(type,"Go Back Button")->Click(); Component<MenuComponent>(type,"Go Back Button")->Click();
}}}, }}},
{game->KEY_SCROLL,{"Scroll Up/Down",[](MenuType type){ {game->KEY_SCROLL,{"Scroll Up/Down",[](MenuType type){
auto&scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List"); auto scrollWindow=Component<ScrollableWindowComponent>(type,"Game Files List");
scrollWindow->SetScrollAmount(scrollWindow->GetScrollAmount()+game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F); scrollWindow->SetScrollAmount(scrollWindow->GetScrollAmount()-vf2d{0,game->KEY_SCROLL.Analog()*game->GetElapsedTime()*"Interface.AnalogScrollSpeed"_F});
for(auto component:scrollWindow->GetComponents()){
if(geom2d::overlaps(scrollWindow->GetPos()+scrollWindow->GetSize()/2,geom2d::rect<float>{component.lock()->GetPos(),component.lock()->GetSize()})){
Menu::menus[type]->SetSelection(component);
}
}
}}}, }}},
} }
,{ //Button Navigation Rules ,{ //Button Navigation Rules

@ -297,7 +297,7 @@ void Menu::KeyboardButtonNavigation(AiL*game,vf2d menuPos){
std::weak_ptr<MenuComponent>prevSelection=selection; std::weak_ptr<MenuComponent>prevSelection=selection;
for(auto&[input,data]:inputGroups){ for(auto&[input,data]:inputGroups){
if(input.Released()){ if(input.Released()||input.Analog()!=0.f){
SetMouseNavigation(false); SetMouseNavigation(false);
auto&action=data.second; auto&action=data.second;
if(std::holds_alternative<ButtonName>(action))Component<MenuComponent>(type,std::get<ButtonName>(action))->Click(); if(std::holds_alternative<ButtonName>(action))Component<MenuComponent>(type,std::get<ButtonName>(action))->Click();
@ -641,6 +641,11 @@ void Menu::SetSelection(std::weak_ptr<MenuComponent>button){
!button.lock()->parentComponent.expired()&&navigationGroups.count(button.lock()->parentComponent.lock()->GetName())){ !button.lock()->parentComponent.expired()&&navigationGroups.count(button.lock()->parentComponent.lock()->GetName())){
keyboardSelection=button; keyboardSelection=button;
} }
if(!UsingMouseNavigation()&&!button.lock()->parentComponent.expired()){
auto scrollWindow=button.lock()->parentComponent.lock();
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[button.lock()->parentMenu]->components[button.lock()->GetName()]);
}
} }
void Menu::SetSelection(std::string_view button){ void Menu::SetSelection(std::string_view button){
@ -649,6 +654,11 @@ void Menu::SetSelection(std::string_view button){
!selection.lock()->parentComponent.expired()&&navigationGroups.count(selection.lock()->parentComponent.lock()->GetName())){ !selection.lock()->parentComponent.expired()&&navigationGroups.count(selection.lock()->parentComponent.lock()->GetName())){
keyboardSelection=selection; keyboardSelection=selection;
} }
if(!UsingMouseNavigation()&&!selection.lock()->parentComponent.expired()){
auto scrollWindow=selection.lock()->parentComponent.lock();
scrollWindow->HandleOutsideDisabledButtonSelection(Menu::menus[selection.lock()->parentMenu]->components[selection.lock()->GetName()]);
}
} }
void Menu::SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button){ void Menu::SetSelection(std::variant<std::string,std::weak_ptr<MenuComponent>>button){

@ -127,7 +127,7 @@ protected:
virtual void OnHover(); virtual void OnHover();
public: public:
MenuType parentMenu=MenuType::ENUM_END; MenuType parentMenu=MenuType::ENUM_END;
std::weak_ptr<MenuComponent>parentComponent{}; std::weak_ptr<ScrollableWindowComponent>parentComponent{};
MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rect<float>rect,std::string label,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,ButtonAttr attributes=ButtonAttr::NONE);
MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,vf2d labelScaling,ButtonAttr attributes=ButtonAttr::NONE); MenuComponent(geom2d::rect<float>rect,std::string label,MenuType menuDest,MenuFunc onClick,vf2d labelScaling,ButtonAttr attributes=ButtonAttr::NONE);

@ -54,7 +54,8 @@ protected:
float scrollBarTop=0; float scrollBarTop=0;
bool scrollBarSelected=false; bool scrollBarSelected=false;
float scrollBarHoverTime=0; float scrollBarHoverTime=0;
vf2d scrollOffset; vf2d scrollOffset{};
vf2d targetScrollOffset{};
protected: protected:
inline bool OnScreen(std::weak_ptr<MenuComponent>component){ inline bool OnScreen(std::weak_ptr<MenuComponent>component){
return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}}); return geom2d::overlaps(geom2d::rect<float>{{},rect.size},geom2d::rect<float>{component.lock()->rect.pos+vf2d{2,2},component.lock()->rect.size-vf2d{2,2}});
@ -86,13 +87,14 @@ public:
CalculateBounds(); CalculateBounds();
} }
virtual inline void SetScrollAmount(vf2d scrollOffset){ virtual inline void SetScrollAmount(vf2d scrollOffset){
this->scrollOffset=scrollOffset; this->targetScrollOffset=scrollOffset;
for(std::weak_ptr<MenuComponent>component:components){
component.lock()->rect.pos=component.lock()->originalPos+scrollOffset;
}
} }
virtual inline vf2d GetScrollAmount(){ virtual inline vf2d GetScrollAmount(){
return scrollOffset; return targetScrollOffset;
}
virtual bool GetHoverState(AiL*game,MenuComponent*child)override{
return geom2d::overlaps(geom2d::rect<float>{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<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos());
} }
protected: protected:
virtual inline void AfterCreate()override{ virtual inline void AfterCreate()override{
@ -141,6 +143,10 @@ protected:
scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f); scrollBarHoverTime=std::max(scrollBarHoverTime-game->GetElapsedTime(),0.f);
} }
for(std::weak_ptr<MenuComponent>component:components){
component.lock()->rect.pos=component.lock()->originalPos+targetScrollOffset;
}
if(game->GetMouseWheel()!=0){ if(game->GetMouseWheel()!=0){
if(game->GetMouseWheel()>0){ if(game->GetMouseWheel()>0){
SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F}); SetScrollAmount(GetScrollAmount()+vf2d{0,"ThemeGlobal.MenuScrollWheelSpeed"_F});
@ -150,8 +156,10 @@ protected:
} }
if(bounds.size.y-rect.size.y>0){ if(bounds.size.y-rect.size.y>0){
scrollOffset.y=std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f);
SetScrollAmount({GetScrollAmount().x,std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f)}); SetScrollAmount({GetScrollAmount().x,std::clamp(GetScrollAmount().y,-(bounds.size.y-rect.size.y),0.f)});
}else{ }else{
scrollOffset.y=0;
SetScrollAmount({GetScrollAmount().x,0}); SetScrollAmount({GetScrollAmount().x,0});
} }
@ -195,10 +203,6 @@ protected:
DrawScrollbar(window,{},focused); DrawScrollbar(window,{},focused);
} }
} }
virtual bool GetHoverState(AiL*game,MenuComponent*child)override{
return geom2d::overlaps(geom2d::rect<float>{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<float>{Menu::menus[parentMenu]->pos+rect.pos+child->rect.pos,child->rect.size},game->GetMousePos());
}
//Calculates the bounds of all components. //Calculates the bounds of all components.
inline void CalculateBounds(){ inline void CalculateBounds(){
bounds={}; bounds={};
@ -228,7 +232,7 @@ public:
std::shared_ptr<T> _AddComponent(std::string key,std::shared_ptr<T>button){ std::shared_ptr<T> _AddComponent(std::string key,std::shared_ptr<T>button){
components.push_back(button); components.push_back(button);
button->renderInMain=false; //Now we are in control! button->renderInMain=false; //Now we are in control!
button->parentComponent=Menu::menus[parentMenu]->components[this->GetName()]; button->parentComponent=DYNAMIC_POINTER_CAST<ScrollableWindowComponent>(Menu::menus[parentMenu]->components[this->GetName()]);
button->disabled=disabled; button->disabled=disabled;
CalculateBounds(); CalculateBounds();
@ -244,7 +248,7 @@ public:
} }
virtual inline bool HandleOutsideDisabledButtonSelection(std::weak_ptr<MenuComponent>disabledButton)override{ virtual inline bool HandleOutsideDisabledButtonSelection(std::weak_ptr<MenuComponent>disabledButton)override{
//Set the offset so the center is highlighted by this button. //Set the offset so the center is highlighted by this button.
SetScrollAmount(vf2d{GetScrollAmount().x,-disabledButton.lock()->rect.pos.y+disabledButton.lock()->rect.size.y}); SetScrollAmount(vf2d{GetScrollAmount().x,GetScrollAmount().y-disabledButton.lock()->rect.pos.y+disabledButton.lock()->rect.size.y});
return true; return true;
}; };
virtual void Cleanup()override{} virtual void Cleanup()override{}

@ -1,6 +1,5 @@
January 1st January 1st
=========== ===========
Fix Listeners so they do not leak! (Add a proper listener class and have all listeners inherit from it.)
The Hub / NPC Interactions The Hub / NPC Interactions
Settings Menu Settings Menu
- Any settings should be saved to the save file! - Any settings should be saved to the save file!
@ -12,7 +11,6 @@ Settings Menu
-We have to save keybinds to the save file. -We have to save keybinds to the save file.
- Fix Stage Completed screen, item displays can hit the scrollbar. - Fix Stage Completed screen, item displays can hit the scrollbar.
- Monster spawn list is not populated in Emscripten?
January 31st January 31st
============ ============
@ -26,15 +24,16 @@ Story proofreading/correcting/storyboarding
- Export/Import Save Files Online/Offline - Export/Import Save Files Online/Offline
- Consider controls for fine-tuning music and how they sound during events.
- Lock up unimplemented classes. - Lock up unimplemented classes.
- Don't enable all stage plates normally. - Don't enable all stage plates normally.
A "Debug" version of the game that simply outputs all std::cout to a file as well (debug.log).
ERR messages become just output messages in release build and won't crash the game. ERR messages become just output messages in release build and won't crash the game.
- Hide mouse cursor during controller play. Reveal it again during mouse play. - Hide mouse cursor during controller play. Reveal it again during mouse play.
- Resource Packs
- Getting hurt has additional effects.
mainMenuWindow->SetupKeyboardNavigation( mainMenuWindow->SetupKeyboardNavigation(

@ -37,9 +37,9 @@ All rights reserved.
#pragma endregion #pragma endregion
#pragma once #pragma once
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 2 #define VERSION_MINOR 3
#define VERSION_PATCH 1 #define VERSION_PATCH 0
#define VERSION_BUILD 6037 #define VERSION_BUILD 6071
#define stringify(a) stringify_(a) #define stringify(a) stringify_(a)
#define stringify_(a) #a #define stringify_(a) #a

@ -1,7 +1,7 @@
Interface Interface
{ {
# In pixels/sec # In pixels/sec
AnalogScrollSpeed = 120 AnalogScrollSpeed = 220
# The size of each side of the 9-patch menu sprite. # The size of each side of the 9-patch menu sprite.
9PatchSize = 24,24 9PatchSize = 24,24

Loading…
Cancel
Save