Correct memory leak in consuming items from inventory. Added overworld menu layout. Warrior Up walk animation has head bobbing like all the others now. Fixed alignment of items for ScrollableWindowComponents, fix scrollbar resizing when parent component has offsets.

This commit is contained in:
sigonasr2 2023-11-11 17:31:53 -06:00
parent 395b2e3ab8
commit 30a5cdc488
33 changed files with 30083 additions and 30093 deletions

View File

@ -49,7 +49,7 @@ void Menu::InitializeClassInfoWindow(){
classInfoWindow->AddComponent("Ability 3 Display",ability3);
classInfoWindow->AddComponent("Right Click Ability Display",rightClickAbility);
MenuComponent*backButton=NEW MenuComponent(CLASS_INFO,{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();});
MenuComponent*backButton=NEW MenuComponent(CLASS_INFO,{{classInfoWindow->center().x/2,healthDisplayLabelPos.y+32*4+abilityIconOffsets.y+12},{classInfoWindow->size.x/2,16}},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;});
classInfoWindow->AddComponent("Back Button",backButton);
}

View File

@ -26,12 +26,13 @@ void Menu::InitializeClassSelectionWindow(){
vf2d navigationButtonSize={24*2.5f,16};
MenuComponent*backButton=NEW MenuComponent(CLASS_SELECTION,{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();});
MenuComponent*backButton=NEW MenuComponent(CLASS_SELECTION,{{4+2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Back",[](MenuFuncData data){Menu::CloseMenu();return true;});
classSelectionWindow->AddComponent("Back Button",backButton);
MenuComponent*confirmButton=NEW MenuComponent(CLASS_SELECTION,{{outlineSize.x+4-navigationButtonSize.x-2,outlineSize.y+4-navigationButtonSize.y-2},navigationButtonSize},"Confirm",[](MenuFuncData data){
std::string selectedClass=data.component->S(A::CLASS_SELECTION);
data.game->ChangePlayerClass(classutils::StringToClass(selectedClass));
GameState::ChangeState(States::OVERWORLD_MAP);
return true;
});
confirmButton->disabled=true;
classSelectionWindow->AddComponent("Confirm",confirmButton);
@ -79,6 +80,7 @@ void Menu::InitializeClassSelectionWindow(){
MenuAnimatedIconToggleButton*classSprite=NEW MenuAnimatedIconToggleButton(CLASS_SELECTION,{backgroundOffsetPos+vf2d{0,12},backgroundSize+vf2d{0,-buttonSize.y-12}},classAnimationName,[](MenuFuncData data){
data.menu.components["Confirm"]->Enable(true);
data.menu.components["Confirm"]->S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
return true;
});
toggleGroup.push_back(classSprite);
MenuComponent*classButton=NEW MenuComponent(CLASS_SELECTION,{offsetPos,buttonSize},"Info",CLASS_INFO,
@ -86,6 +88,7 @@ void Menu::InitializeClassSelectionWindow(){
data.menu.S(A::CLASS_SELECTION)=data.component->S(A::CLASS_SELECTION);
delete Menu::menus[CLASS_INFO];
Menu::InitializeClassInfoWindow();
return true;
});
classSprite->S(A::CLASS_SELECTION)=classButton->S(A::CLASS_SELECTION)=className;
classSelectionWindow->AddComponent(className+" Button",classButton);

View File

@ -1368,11 +1368,7 @@ void Crawler::LoadLevel(MapName map){
player->SetPos(MAP_DATA[map].MapData.playerSpawnLocation);
vf2d cameraStartPos=player->GetPos()+vf2d(-24*6,0);
camera.SetMode(Camera2D::Mode::Simple);
camera.SetTarget(cameraStartPos);
camera.Update(game->GetElapsedTime());
camera.SetMode(Camera2D::Mode::LazyFollow);
camera.SetTarget(player->GetPos());
camera.MoveCamera(cameraStartPos);
pathfinder.Initialize();
}
@ -1779,7 +1775,9 @@ void Crawler::RenderMenu(){
Menu::stack.back()->Update(this);
}
if(Menu::stack.size()>0){
FillRectDecal({0,0},WINDOW_SIZE,{0,0,0,uint8_t(255*0.4)});
if(Menu::cover){
FillRectDecal({0,0},WINDOW_SIZE,{0,0,0,uint8_t(255*0.4)});
}
for(Menu*menu:Menu::stack){
menu->Draw(this);
}
@ -1883,4 +1881,12 @@ void Crawler::ValidateGameStatus(){
void Crawler::RenderVersionInfo(){
std::string versionStr("v" + std::to_string(VERSION_MAJOR) + "." + std::to_string(VERSION_MINOR) + "." + std::to_string(VERSION_PATCH) + "." + std::to_string(VERSION_BUILD));
DrawShadowStringDecal(vf2d{ GetScreenSize() } - vf2d{ GetTextSize(versionStr) }*0.4,versionStr,WHITE,BLACK,{0.4,0.4},0.4);
}
int Crawler::GetCurrentChapter(){
return chapter;
}
void Crawler::SetChapter(int chapter){
this->chapter=chapter;
}

View File

@ -28,11 +28,11 @@ public:
static float SIZE_CHANGE_SPEED;
float levelTime;
Camera2D camera;
std::map<MapName,Map>MAP_DATA;
private:
std::vector<std::unique_ptr<Effect>>foregroundEffects,backgroundEffects,foregroundEffectsToBeInserted,backgroundEffectsToBeInserted;
std::vector<TileRenderData*>tilePreparationList,tileForegroundList;
std::vector<vf2d>circleCooldownPoints;
std::map<MapName,Map>MAP_DATA;
std::map<std::string,TilesetData>MAP_TILESETS;
vf2d worldShake={};
float worldShakeTime=0;
@ -58,6 +58,7 @@ private:
float encounterDuration=0;
bool encounterStarted=false;
int totalBossEncounterMobs=0;
int chapter=1; //We start at chapter 1.
std::vector<Monster>monstersToBeSpawned;
@ -135,6 +136,8 @@ public:
void InitializeGraphics();
void RenderVersionInfo();
MapTag GetCurrentMap();
int GetCurrentChapter();
void SetChapter(int chapter);
struct TileGroupData{
vi2d tilePos;

View File

@ -343,6 +343,7 @@
<ClCompile Include="MenuComponent.cpp" />
<ClCompile Include="Meteor.cpp" />
<ClCompile Include="OverworldDisplayWindow.cpp" />
<ClCompile Include="OverworldMapLevelWindow.cpp" />
<ClCompile Include="RunAway.cpp" />
<ClCompile Include="RunTowards.cpp" />
<ClCompile Include="Pathfinding.cpp" />

View File

@ -389,6 +389,9 @@
<ClCompile Include="OverworldDisplayWindow.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
<ClCompile Include="OverworldMapLevelWindow.cpp">
<Filter>Source Files\Interface</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="cpp.hint" />

View File

@ -15,7 +15,8 @@
#define INCLUDE_GFX extern safemap<std::string,Renderable>GFX;
#define INCLUDE_ITEM_DATA extern safemap<std::string,ItemInfo>ITEM_DATA;
#define INCLUDE_ITEM_CATEGORIES extern safemap<std::string,std::set<std::string>>ITEM_CATEGORIES;
#define DO_NOTHING [](MenuFuncData data){}
#define DO_NOTHING [](MenuFuncData data){return true;}
#define INCLUDE_LEVEL_NAMES extern safemap<std::string,MapName>LEVEL_NAMES;
#define ACCESS_PLAYER Player*p=game->GetPlayer();

View File

@ -10,7 +10,7 @@ void GameState::Initialize(){
NEW_STATE(States::OVERWORLD_MAP,State_OverworldMap);
NEW_STATE(States::MAIN_MENU,State_MainMenu);
GameState::ChangeState(States::GAME_RUN);
GameState::ChangeState(States::OVERWORLD_MAP);
}
GameState::~GameState(){}

View File

@ -10,8 +10,8 @@ typedef Attribute A;
class InventoryScrollableWindowComponent:public ScrollableWindowComponent{
protected:
public:
inline InventoryScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuFunc onClick)
:ScrollableWindowComponent(parent,rect,icon,onClick){}
inline InventoryScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:ScrollableWindowComponent(parent,rect,attributes){}
protected:
virtual inline void RemoveButton(MenuComponent*button){
std::vector<MenuComponent*>&buttonList=Menu::menus[button->parentMenu]->buttons.at(button->GetPos().y);
@ -21,8 +21,6 @@ protected:
removedCount+=std::erase(keyboardButtonList,button);
if(removedCount!=2){
std::cout<<"WARNING! Attempted to remove buttons from button listing, but not found!";
;
}
if(buttonList.size()==0){
if(!Menu::menus[button->parentMenu]->buttons.erase(button->GetPos().y)){
@ -54,6 +52,7 @@ protected:
//Now delete the last slot.
components.erase(components.end()-1);
i--; //Subtract one from the index so we don't accidently skip slots.
delete lastButton;
}
}
bounds=CalculateBounds(); //Recalculate the bounds as it's possible the width/height of the component has changed.
@ -72,7 +71,7 @@ protected:
MenuFunc useItemFunc=[](MenuFuncData data){
MenuItemButton*button=(MenuItemButton*)data.component;
button->UseItem();
return !button->UseItem();
};
MenuItemButton*button=NEW MenuItemButton{parentMenu,{{float(totalSpacing*x),float(totalSpacing*y)},{float(buttonSize),float(buttonSize)}},Inventory::get("Consumables"),itemIndex,useItemFunc};

View File

@ -21,7 +21,7 @@ void Menu::InitializeInventoryWindow(){
Menu*inventoryWindow=CreateMenu(INVENTORY,CENTERED,windowSize);
InventoryScrollableWindowComponent*inventory=NEW InventoryScrollableWindowComponent(INVENTORY,{{1,0},{windowSize.x,float(totalSpacing*3-itemSpacing)}},nullptr,[](MenuFuncData data){});
InventoryScrollableWindowComponent*inventory=NEW InventoryScrollableWindowComponent(INVENTORY,{{1,0},{windowSize.x,float(totalSpacing*3-itemSpacing)}});
inventoryWindow->AddComponent("inventory",inventory);
Menu::AddInventoryListener(inventory,"Consumables");
Menu::AddInventoryListener(inventory,"Equipment");

View File

@ -137,19 +137,22 @@ uint32_t Inventory::GetItemCount(IT it){
}
}
void Inventory::UseItem(IT it,uint32_t amt){
if(!_inventory.count(it))return;
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
bool Inventory::UseItem(IT it,uint32_t amt){
if(!_inventory.count(it))return false;
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
for(int i=0;i<amt;i++){
if(ExecuteAction(it)){
RemoveItem(it);
return RemoveItem(it);
}
}
return false;
}
void Inventory::RemoveItem(IT it,uint32_t amt){
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
bool Inventory::RemoveItem(IT it,uint32_t amt){
//There are two places to manipulate items in (Both the sorted inventory and the actual inventory)
if(!_inventory.count(it))return;
if(!_inventory.count(it))return false;
if(amt>=_inventory.at(it).Amt()){
int count=0;
std::vector<IT>&sortedList=sortedInv.at(_inventory.at(it).Category());
@ -162,8 +165,10 @@ void Inventory::RemoveItem(IT it,uint32_t amt){
ITCategory cat=ITEM_DATA[it].category;
//Callback for GUI inventories.
Menu::InventorySlotsUpdated(cat);
return true;
}else{
_inventory.at(it).amt-=amt;
return false;
}
}

View File

@ -40,8 +40,8 @@ public:
static uint32_t GetItemCount(IT it);
static Item GetItem(IT it);
//Auto-executes its use function and removes the amt specified from the inventory. Multiple amounts will cause the item to execute its useFunc multiple times.
static void UseItem(IT it,uint32_t amt=1);
static void RemoveItem(IT it,uint32_t amt=1);
static bool UseItem(IT it,uint32_t amt=1);
static bool RemoveItem(IT it,uint32_t amt=1);
static std::vector<IT>&get(ITCategory itemCategory);
static bool SwapItems(ITCategory itemCategory,uint32_t slot1,uint32_t slot2);

View File

@ -1,11 +1,17 @@
#include "Map.h"
#include "Crawler.h"
#include "safemap.h"
INCLUDE_game
INCLUDE_LEVEL_NAMES
float TileGroup::FADE_TIME=0.3;
uint8_t TileGroup::FADE_AMT=160;
Map&MapHelper::MapFromString(std::string mapName){
return game->MAP_DATA[LEVEL_NAMES[mapName]];
}
void TileGroup::InsertTile(TileRenderData tile){
if(tiles.size()==0){
range={tile.pos,{game->GetCurrentMap().tilewidth,game->GetCurrentMap().tilewidth}};

View File

@ -1,6 +1,7 @@
#pragma once
#include "olcUTIL_Geometry2D.h"
#include <set>
#include "TMXParser.h"
struct XMLTag;
@ -11,6 +12,11 @@ enum MapName{
WORLD_MAP
};
class MapHelper{
public:
static Map&MapFromString(std::string mapName);
};
struct TileCollisionData{
geom2d::rect<int>collision;
};

View File

@ -28,6 +28,7 @@ std::vector<MenuComponent*>Menu::unhandledComponents;
//////////////////////////////////////////////////////////////////////////////////////////////////
MenuType Menu::lastMenuTypeCreated;
std::string Menu::lastRegisteredComponent;
bool Menu::cover;
INCLUDE_GFX
extern vi2d WINDOW_SIZE;
@ -54,6 +55,7 @@ void Menu::InitializeMenus(){
InitializeClassSelectionWindow();
InitializeClassInfoWindow();
InitializeMainMenuWindow();
InitializeOverworldMapLevelWindow();
for(MenuType type=TEST;type<MenuType::ENUM_END;type=MenuType(int(type+1))){
if(menus.count(type)==0){
@ -154,12 +156,14 @@ void Menu::HoverMenuSelect(Crawler*game){
void Menu::MenuSelect(Crawler*game){
if(selection==vi2d{-1,-1}||buttons[selection.y][selection.x]->disabled)return;
buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x]});
if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
if(stack.size()<32){
stack.push_back(menus[buttons[selection.y][selection.x]->menuDest]);//Navigate to the next menu.
}else{
ERR("WARNING! Exceeded menu stack size limit!")
bool buttonStillValid=buttons[selection.y][selection.x]->onClick(MenuFuncData{*this,game,buttons[selection.y][selection.x]});
if(buttonStillValid){
if(buttons[selection.y][selection.x]->menuDest!=MenuType::ENUM_END){
if(stack.size()<32){
stack.push_back(menus[buttons[selection.y][selection.x]->menuDest]);//Navigate to the next menu.
}else{
ERR("WARNING! Exceeded menu stack size limit!")
}
}
}
}
@ -339,7 +343,8 @@ void Menu::Draw(Crawler*game){
}
};
void Menu::OpenMenu(MenuType menu){
void Menu::OpenMenu(MenuType menu,bool cover){
Menu::cover=cover;
stack.clear();
stack.push_back(menus[menu]);
}

View File

@ -16,6 +16,7 @@ enum MenuType{
CLASS_INFO,
CLASS_SELECTION,
MAIN_MENU,
OVERWORLD_LEVEL_SELECT,
///////////////////////////////////////////////////////////
/*DO NOT REMOVE!!*/ENUM_END////////////////////////////////
///////////////////////////////////////////////////////////
@ -41,7 +42,7 @@ public:
void Update(Crawler*game);
void Draw(Crawler*game);
static void InitializeMenus();
static void OpenMenu(MenuType menu);
static void OpenMenu(MenuType menu,bool cover=true);
static void CloseMenu();
static void CloseAllMenus();
static void CleanupAllMenus();
@ -83,6 +84,7 @@ private:
static void InitializeClassInfoWindow();
static void InitializeClassSelectionWindow();
static void InitializeMainMenuWindow();
static void InitializeOverworldMapLevelWindow();
//X (0-2), Y (0-2) for specific 9-patch tile (tiled version).
static Renderable&GetPatchPart(int x,int y);
@ -97,6 +99,7 @@ private:
Pixel GetRenderColor();
static bool MOUSE_NAVIGATION;
static bool cover; //A black cover for when a menu pops up to fade out the stuff behind it.
};
struct MenuFuncData{
@ -105,4 +108,4 @@ struct MenuFuncData{
MenuComponent*component;
};
typedef std::function<void(MenuFuncData)> MenuFunc;
typedef std::function<bool(MenuFuncData)> MenuFunc;

View File

@ -17,6 +17,7 @@ public:
MenuAnimatedIconToggleButton*button=(MenuAnimatedIconToggleButton*)data.component;
button->Select();
button->_onClick(data);
return true;
}),_onClick(onClick){}
protected:
virtual inline void Update(Crawler*game)override{

View File

@ -46,13 +46,13 @@ void MenuComponent::_Update(Crawler*game){
void MenuComponent::Draw(Crawler*game,vf2d parentPos){
if(background){
game->FillRect(rect.pos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
game->FillRect(rect.pos+parentPos,rect.size,PixelLerp(Menu::themes[Menu::themeSelection].GetButtonCol(),Menu::themes[Menu::themeSelection].GetHighlightCol(),hoverEffect/"ThemeGlobal.HighlightTime"_F));
}
if(border){
game->DrawRect(rect.pos,rect.size);
game->DrawRect(rect.pos+parentPos,rect.size);
}
if(showDefaultLabel){
game->DrawStringProp(rect.pos+rect.size/2-game->GetTextSizeProp(label)/2,label);
game->DrawStringProp(rect.pos+parentPos+rect.size/2-game->GetTextSizeProp(label)/2,label);
}
}

View File

@ -22,8 +22,9 @@ public:
inline Item GetItem(){
return Inventory::GetItem(invRef.at(inventoryIndex));
}
inline void UseItem(uint32_t amt=1){
if(invRef.size()<=inventoryIndex)return;
//Returns true if the item has been consumed completely and there are 0 remaining of that type in our inventory.
inline bool UseItem(uint32_t amt=1){
if(invRef.size()<=inventoryIndex)return false;
return Inventory::UseItem(invRef.at(inventoryIndex),amt);
}
protected:

View File

@ -51,6 +51,7 @@ struct MonsterData{
std::vector<std::string>GetAnimations(){
return animations;
}
std::string GetDisplayName();
static void InitializeMonsterData();
static std::map<int,Renderable*>imgs;
};

View File

@ -127,6 +127,9 @@ int MonsterData::GetID(){
int MonsterData::GetAIStrategy(){
return strategy;
}
std::string MonsterData::GetDisplayName(){
return name;
}
std::string MonsterData::GetIdleAnimation(){
return animations[IDLE];

View File

@ -0,0 +1,52 @@
#pragma once
#include "Crawler.h"
#include "DEFINES.h"
#include "Menu.h"
#include "ScrollableWindowComponent.h"
#include "MenuLabel.h"
#include "MenuComponent.h"
#include "State_OverworldMap.h"
#include "Map.h"
INCLUDE_game
INCLUDE_LEVEL_NAMES
INCLUDE_MONSTER_DATA
typedef Attribute A;
void Menu::InitializeOverworldMapLevelWindow(){
vf2d windowSize={game->GetScreenSize().x/3.f-24,float(game->GetScreenSize().y)-48};
Menu*levelSelectWindow=CreateMenu(OVERWORLD_LEVEL_SELECT,{game->GetScreenSize().x-game->GetScreenSize().x/3.f,24},windowSize);
State_OverworldMap*overworldMap=(State_OverworldMap*)GameState::states[States::OVERWORLD_MAP]; //HACK ALERT!! We're going to make an assumption that we are in the overworld map state.
//Map&loadedMap=MapHelper::MapFromString(overworldMap->GetCurrentConnectionPoint().map);
//std::set<int>&spawns=loadedMap.spawns;
/*int yOffset=40;
for(int key:spawns){
MenuLabel*testLabel=new MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,float(yOffset)},{windowSize.x,24}},MONSTER_DATA[key].GetDisplayName());
yOffset+=28;
levelSelectWindow->AddComponent(MONSTER_DATA[key].GetDisplayName()+" Display Label",testLabel);
}*/
MenuLabel*chapterLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,4},{windowSize.x,16}},"Chapter "+std::to_string(game->GetCurrentChapter()),1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
MenuLabel*stageLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,24},{windowSize.x,16}},"Stage",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
MenuLabel*panel1Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,0},{windowSize.x-1,44}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
levelSelectWindow->AddComponent("Panel 1 Back",panel1Back);
levelSelectWindow->AddComponent("Chapter Label",chapterLabel);
levelSelectWindow->AddComponent("Stage Label",stageLabel);
MenuLabel*encountersLabel=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,12}},"Encounters:",1,ComponentAttr::SHADOW|ComponentAttr::LEFT_ALIGN);
ScrollableWindowComponent*spawns=NEW ScrollableWindowComponent(OVERWORLD_LEVEL_SELECT,{{1,64},{windowSize.x-2,84}},ComponentAttr::BACKGROUND);
MenuLabel*panel2Back=NEW MenuLabel(OVERWORLD_LEVEL_SELECT,{{0,52},{windowSize.x-1,96}},"",1,ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE);
levelSelectWindow->AddComponent("Panel 2 Back",panel2Back);
levelSelectWindow->AddComponent("Encounters Label",encountersLabel);
levelSelectWindow->AddComponent("Spawns List",spawns);
MenuComponent*changeLoadoutButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,152},{windowSize.x-1,12}},"Change Loadout",INVENTORY,[](MenuFuncData data){return true;});
MenuComponent*enterButton=NEW MenuComponent(OVERWORLD_LEVEL_SELECT,{{0,166},{windowSize.x-1,16}},"Enter",[](MenuFuncData data){return true;});
levelSelectWindow->AddComponent("Change Loadout Button",changeLoadoutButton);
levelSelectWindow->AddComponent("Enter Button",enterButton);
}

View File

@ -22,14 +22,16 @@ protected:
return geom2d::overlaps(rect,geom2d::rect<float>{component->rect.pos+V(A::SCROLL_OFFSET)+vf2d{2,2},component->rect.size-vf2d{2,2}});
}
public:
inline ScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,Decal*icon,MenuFunc onClick)
:MenuComponent(parent,rect,"",onClick,ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
inline ScrollableWindowComponent(MenuType parent,geom2d::rect<float>rect,ComponentAttr attributes=ComponentAttr::BACKGROUND|ComponentAttr::OUTLINE)
:MenuComponent(parent,rect,"",[](MenuFuncData data){return true;},ButtonAttr::UNSELECTABLE|ButtonAttr::UNSELECTABLE_VIA_KEYBOARD){
background=attributes&ComponentAttr::BACKGROUND;
border=attributes&ComponentAttr::OUTLINE;
r.Create(rect.size.x,rect.size.y);
}
protected:
virtual inline void AfterCreate()override{
upButton=NEW MenuComponent(parentMenu,{vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
downButton=NEW MenuComponent(parentMenu,{rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
upButton=NEW MenuComponent(parentMenu,{rect.pos+vf2d{rect.size.x-12,0},{12,12}},"^",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y+="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
downButton=NEW MenuComponent(parentMenu,{rect.pos+rect.size-vf2d{12,12},{12,12}},"v",[&](MenuFuncData dat){V(A::SCROLL_OFFSET).y-="ThemeGlobal.MenuButtonScrollSpeed"_I;return true;},ButtonAttr::UNSELECTABLE_VIA_KEYBOARD);
//Let's use the internal name of this component to add unique names for sub-components.
Menu::menus[parentMenu]->AddComponent(name+upButton->rect.pos.str()+"_"+upButton->rect.size.str(),upButton);
Menu::menus[parentMenu]->AddComponent(name+downButton->rect.pos.str()+"_"+downButton->rect.size.str(),downButton);
@ -56,6 +58,7 @@ protected:
float totalContentHeight=bounds.size.y;
if(totalContentHeight==0)totalContentHeight=1;
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
//The scroll amount moves centered on the position the mouse is at.
float newScrollbarTop=(game->GetMousePos().y-windowAbsPos.y-12)-scrollBarHeight/2;
@ -73,7 +76,11 @@ protected:
}
}
V(A::SCROLL_OFFSET).y=std::clamp(V(A::SCROLL_OFFSET).y,-(bounds.size.y-rect.size.y),0.f);
if(bounds.size.y-rect.size.y>0){
V(A::SCROLL_OFFSET).y=std::clamp(V(A::SCROLL_OFFSET).y,-(bounds.size.y-rect.size.y),0.f);
}else{
V(A::SCROLL_OFFSET).y=0;
}
for(MenuComponent*component:components){
component->disabled=!OnScreen(component);
@ -103,19 +110,22 @@ protected:
float spaceBetweenTopAndBottomArrows=rect.size.y-24;
float viewHeight=rect.size.y;
float totalContentHeight=bounds.size.y;
if(totalContentHeight==0)totalContentHeight=1;
float scrollBarScale=(spaceBetweenTopAndBottomArrows/totalContentHeight);
scrollBarHeight=viewHeight*scrollBarScale-1;
scrollBarHeight=std::min(spaceBetweenTopAndBottomArrows,viewHeight*scrollBarScale-1);
scrollBarTop=-V(A::SCROLL_OFFSET).y*scrollBarScale+1;
float focusedWindowColorMult=(focused?1:"ThemeGlobal.MenuUnfocusedColorMult"_F);
game->FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-13,scrollBarTop+12},{12,scrollBarHeight},PixelLerp(Menu::GetCurrentTheme().GetButtonCol(),Menu::GetCurrentTheme().GetHighlightCol(),scrollBarHoverTime/"ThemeGlobal.HighlightTime"_F)*focusedWindowColorMult);
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-13,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
game->FillRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},PixelLerp(Menu::GetCurrentTheme().GetButtonCol(),Menu::GetCurrentTheme().GetHighlightCol(),scrollBarHoverTime/"ThemeGlobal.HighlightTime"_F)*focusedWindowColorMult);
game->DrawRectDecal(rect.pos+parentPos+vf2d{rect.size.x-11.75f,scrollBarTop+12},{12,scrollBarHeight},WHITE*focusedWindowColorMult);
}
virtual inline void DrawDecal(Crawler*game,vf2d parentPos,bool focused)override{
MenuComponent::DrawDecal(game,parentPos,focused);
game->DrawRectDecal(rect.pos+Menu::menus[parentMenu]->pos,rect.size);
if(border){
game->DrawRectDecal(rect.pos+Menu::menus[parentMenu]->pos,rect.size);
}
for(MenuComponent*component:components){
component->_DrawDecal(game,rect.pos+Menu::menus[parentMenu]->pos+V(A::SCROLL_OFFSET),focused);
}

View File

@ -24,6 +24,8 @@ void State_OverworldMap::OnStateChange(GameState*prevState){
game->GetPlayer()->UpdateWalkingAnimation(DOWN);
game->GetPlayer()->SetState(State::FORCE_WALK);
game->GetPlayer()->SetSizeMult(1);
game->camera.MoveCamera(game->GetPlayer()->GetPos());
Menu::OpenMenu(OVERWORLD_LEVEL_SELECT,false);
};
void State_OverworldMap::OnUserUpdate(Crawler*game){
game->camera.SetTarget(currentConnectionPoint->rect.middle()+vf2d{game->GetScreenSize().x/6.0f,0});

View File

@ -2,6 +2,7 @@
#include "olcPixelGameEngine.h"
#include "olcUTIL_Geometry2D.h"
#include <sstream>
#include <set>
using namespace olc;
@ -49,6 +50,7 @@ struct Map{
Renderable*optimizedTile=nullptr;
std::vector<XMLTag> TilesetData;
std::vector<LayerTag> LayerData;
std::set<int>spawns;
std::map<int,SpawnerTag> SpawnerData; //Spawn groups have IDs, mobs associate which spawner they are tied to via this ID.
std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
std::string FormatLayerData(std::ostream& os, std::vector<LayerTag>tiles);
@ -256,7 +258,7 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
XMLTag newTag=ReadNextTag();
if (newTag.tag=="object"&&newTag.data["type"]!="StagePlate") {
if (newTag.tag=="object"&&newTag.data["type"]!="StagePlate"){
currentStagePlate=nullptr;
}
@ -274,7 +276,7 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
LayerTag l = {newTag};
parsedMapInfo.LayerData.push_back(l);
}else
if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup") {
if (newTag.tag=="object"&&newTag.data["type"]=="SpawnGroup"){
if(newTag.GetInteger("id")!=0){
parsedMapInfo.SpawnerData[newTag.GetInteger("id")]={newTag};
prevSpawner=newTag.GetInteger("id");
@ -310,6 +312,7 @@ typedef std::map<std::string,std::vector<geom2d::rect<int>>> ZoneData;
} else
if (newTag.tag=="property"&&monsterPropertyTagCount==0) {
monsterTag.data["value"]=newTag.data["value"];
parsedMapInfo.spawns.insert(newTag.GetInteger("value"));
monsterPropertyTagCount++;
} else
if (newTag.tag=="property"&&monsterPropertyTagCount==1) {

View File

@ -6,16 +6,18 @@ void Menu::InitializeTestMenu(){
MenuFunc quitWindow=[](MenuFuncData data){
data.menu.stack.clear();
return true;
};
testMenu->AddComponent("Close",NEW MenuComponent(TEST,{{24*1,24*1},{24*2,24*1}},"Close",quitWindow));
MenuFunc doNothing=[](MenuFuncData data){};
MenuFunc doNothing=[](MenuFuncData data){return true;};
testMenu->AddComponent("Test",NEW MenuComponent(TEST,{{24*4,24*1},{24*3,24*1}},"Test",doNothing));
MenuFunc HurtPlayer=[](MenuFuncData data){
data.game->GetPlayer()->Hurt(20,data.game->GetPlayer()->OnUpperLevel(),data.game->GetPlayer()->GetZ());
return true;
};
testMenu->AddComponent("Hurt Player",NEW MenuComponent(TEST,{{24*4,24*3},{24*3,24*1}},"Hurt Player",HurtPlayer));

View File

@ -13,6 +13,7 @@ void Menu::InitializeTestSubMenu(){
MenuFunc goBack=[](MenuFuncData data){
data.menu.stack.pop_back();
return true;
};
testSubMenu->AddComponent("BACK",NEW MenuComponent(TEST_2,{{24*1,24*1},{24*2,24*1}},"Go Back",goBack));
@ -41,6 +42,7 @@ void Menu::InitializeTestSubMenu(){
}
index++;
}
return true;
};
testSubMenu->AddComponent("PREV_THEME",NEW MenuComponent(TEST_2,{{24*-0.5,24*3},{24*1,24*1}},"<",themePrev));
@ -58,6 +60,7 @@ void Menu::InitializeTestSubMenu(){
}
index++;
}
return true;
};
testSubMenu->AddComponent("NEXT_THEME",NEW MenuComponent(TEST_2,{{24*3.5,24*3},{24*1,24*1}},">",themeNext));

View File

@ -2,7 +2,7 @@
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_PATCH 1
#define VERSION_BUILD 2642
#define VERSION_BUILD 2718
#define stringify(a) stringify_(a)
#define stringify_(a) #a

View File

@ -16,7 +16,7 @@ Interface
map_config = levels.txt
# Starting map when loading the game.
starting_map = CAMPAIGN_1_1
starting_map = WORLD_MAP
# Player Properties Loading Config
player_config = Player.txt

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

View File

@ -183,6 +183,17 @@ namespace olc::utils
return m_vEdgeTriggerDistance;
}
// Directly moves the camera to a new point, useful when transitioning areas.
inline void MoveCamera(vf2d pos){
Mode prevMode=m_nMode;
vf2d&prevTarget=*m_pTarget;
SetMode(Mode::Simple);
SetTarget(pos);
Update(0);
SetMode(prevMode);
SetTarget(prevTarget);
}
// Update camera, animating if necessary, obeying world boundary rules
// returns true if target is visible
inline virtual bool Update(const float fElapsedTime)