diff --git a/assets/button2.png b/assets/button2.png new file mode 100644 index 0000000..0703157 Binary files /dev/null and b/assets/button2.png differ diff --git a/assets/button3.png b/assets/button3.png new file mode 100644 index 0000000..f65f7da Binary files /dev/null and b/assets/button3.png differ diff --git a/assets/button4.png b/assets/button4.png new file mode 100644 index 0000000..deb6394 Binary files /dev/null and b/assets/button4.png differ diff --git a/assets/highlight_button2.png b/assets/highlight_button2.png new file mode 100644 index 0000000..3a6ee0b Binary files /dev/null and b/assets/highlight_button2.png differ diff --git a/assets/highlight_button3.png b/assets/highlight_button3.png new file mode 100644 index 0000000..b4c9646 Binary files /dev/null and b/assets/highlight_button3.png differ diff --git a/assets/highlight_button4.png b/assets/highlight_button4.png new file mode 100644 index 0000000..fd6022b Binary files /dev/null and b/assets/highlight_button4.png differ diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index ddd2313..da06f8a 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -108,6 +108,13 @@ void HamsterGame::LoadGraphics(){ _LoadImage("hamsterplanet2.png"); _LoadImage("hamsterplanet3.png"); _LoadImage("button.png"); + _LoadImage("highlight_button.png"); + _LoadImage("button2.png"); + _LoadImage("highlight_button2.png"); + _LoadImage("button3.png"); + _LoadImage("highlight_button3.png"); + _LoadImage("button4.png"); + _LoadImage("highlight_button4.png"); } void HamsterGame::LoadAnimations(){ @@ -359,7 +366,7 @@ bool HamsterGame::OnUserUpdate(float fElapsedTime){ runTime+=fElapsedTime; menu.UpdateAndDraw(*this,fElapsedTime); - return true; + return gameIsRunning; } const Renderable&HamsterGame::GetGFX(const std::string&img){ @@ -682,6 +689,10 @@ void HamsterGame::ProcessMap(){ SetDrawTarget(nullptr); } +void HamsterGame::QuitGame(){ + gameIsRunning=false; +} + int main() { HamsterGame game("Project Hamster"); diff --git a/src/HamsterGame.h b/src/HamsterGame.h index d9c161a..e9aa16b 100644 --- a/src/HamsterGame.h +++ b/src/HamsterGame.h @@ -111,6 +111,7 @@ public: const bool HasMoreMapsToPlay()const; const std::string PopNextMap(); void ProcessMap(); + void QuitGame(); private: void UpdateGame(const float fElapsedTime); void DrawGame(); @@ -193,4 +194,5 @@ private: size_t loadingMapLayerTileY; int totalOperationsCount{}; int operationsProgress{}; + bool gameIsRunning{true}; }; \ No newline at end of file diff --git a/src/Menu.cpp b/src/Menu.cpp index f0442f4..57b35d0 100644 --- a/src/Menu.cpp +++ b/src/Menu.cpp @@ -43,10 +43,33 @@ All rights reserved. void Menu::UpdateAndDraw(HamsterGame&game,const float fElapsedTime){ menuTransitionRefreshTimer-=fElapsedTime; + + for(int i{0};const Button&b:menuButtons){ + if(b.IsHovered(oldLayerPos+game.SCREEN_FRAME.pos))selectedButton=i; + i++; + } + + if(menuButtons.size()>0&&menuTimer==0.f){ + if(game.GetKey(W).bPressed||game.GetKey(UP).bPressed||game.GetKey(A).bPressed||game.GetKey(LEFT).bPressed){ + if(selectedButton.value()-1<0)selectedButton=menuButtons.size()-1; + else selectedButton.value()--; + } + if(game.GetKey(S).bPressed||game.GetKey(DOWN).bPressed||game.GetKey(D).bPressed||game.GetKey(RIGHT).bPressed){ + if(selectedButton.value()+1>=menuButtons.size())selectedButton=0; + else selectedButton.value()++; + } + if(game.GetKey(ENTER).bPressed||game.GetKey(SPACE).bPressed||menuButtons[selectedButton.value()].IsHovered(oldLayerPos+game.SCREEN_FRAME.pos)&&game.GetMouse(Mouse::LEFT).bPressed){ + menuButtons[selectedButton.value()].OnClick(); + } + } + if(menuTimer>0.f){ menuTimer-=fElapsedTime; if(menuTimer<=0.f){ + menuTimer=0.f; currentMenu=nextMenu; + oldLayerPos={}; + newLayerPos=game.SCREEN_FRAME.pos; OnMenuTransition(); } } @@ -58,15 +81,11 @@ void Menu::UpdateAndDraw(HamsterGame&game,const float fElapsedTime){ Transition(FADE_OUT,TITLE_SCREEN,1.f); }break; case TITLE_SCREEN:{ - if(game.GetKey(SPACE).bPressed||game.GetMouse(Mouse::LEFT).bPressed){ + if(game.GetKey(SPACE).bPressed||game.GetKey(ENTER).bPressed||game.GetMouse(Mouse::LEFT).bPressed){ Transition(SHIFT_LEFT,MAIN_MENU,0.5f); } }break; case MAIN_MENU:{ - if(game.GetKey(SPACE).bPressed||game.GetMouse(Mouse::LEFT).bPressed){ - Transition(FADE_OUT,LOADING,0.5f); - selectedMap="StageV.tmx"; - } }break; case GAMEPLAY:{ game.UpdateGame(fElapsedTime); @@ -96,20 +115,49 @@ void Menu::Transition(const TransitionType type,const MenuType gotoMenu,const fl menuTimer=originalMenuTimer=transitionTime; nextMenu=gotoMenu; currentTransition=type; + newMenuButtons=GetMenuButtons(gotoMenu); +} +std::vectorMenu::GetMenuButtons(const MenuType type){ + std::vectorbuttons; + switch(type){ + case MAIN_MENU:{ + buttons.emplace_back(HamsterGame::SCREEN_FRAME.size/2+vf2d{0.f,-32.f},"Grand Prix","button.png","highlight_button.png",Pixel{165,208,96},Pixel{37,134,139},[this](){Transition(SHIFT_LEFT,GRAND_PRIX,0.5f);}); + buttons.emplace_back(HamsterGame::SCREEN_FRAME.size/2+vf2d{0.f,0.f},"Single Race","button.png","highlight_button.png",Pixel{165,208,96},Pixel{37,134,139},[this](){Transition(SHIFT_UP,SINGLE_RACE,0.5f);}); + buttons.emplace_back(HamsterGame::SCREEN_FRAME.size/2+vf2d{0.f,32.f},"Options","button.png","highlight_button.png",Pixel{165,208,96},Pixel{37,134,139},[this](){Transition(SHIFT_RIGHT,OPTIONS,0.5f);}); + buttons.emplace_back(HamsterGame::SCREEN_FRAME.size/2+vf2d{0.f,64.f},"Quit","button.png","highlight_button.png",Pixel{165,208,96},Pixel{37,134,139},[this](){Transition(SHIFT_DOWN,QUIT,0.5f);}); + }break; + case GRAND_PRIX:{ + //Add more buttons up here! + buttons.emplace_back(vf2d{54.f,HamsterGame::SCREEN_FRAME.size.y-24.f},"< Back","button3.png","highlight_button3.png",Pixel{145,199,255},Pixel{145,199,255},[this](){Transition(SHIFT_RIGHT,MAIN_MENU,0.5f);}); + }break; + case SINGLE_RACE:{ + //Add more buttons up here! + buttons.emplace_back(vf2d{54.f,HamsterGame::SCREEN_FRAME.size.y-24.f},"< Back","button4.png","highlight_button4.png",Pixel{220,185,155},Pixel{180,140,152},[this](){Transition(SHIFT_DOWN,MAIN_MENU,0.5f);}); + }break; + case OPTIONS:{ + //Add more buttons up here! + buttons.emplace_back(vf2d{54.f,HamsterGame::SCREEN_FRAME.size.y-24.f},"< Back","button2.png","highlight_button2.png",Pixel{114,109,163},Pixel{79,81,128},[this](){Transition(SHIFT_LEFT,MAIN_MENU,0.5f);}); + }break; + } + return buttons; } void Menu::OnMenuTransition(){ selectedButton.reset(); + menuButtons.clear(); + newMenuButtons.clear(); + menuButtons=GetMenuButtons(currentMenu); switch(currentMenu){ - case MAIN_MENU:{ - //selectedButton - }break; case LOADING:{ colorNumb=util::random()%8+1; loading=true; loadingPct=0.f; HamsterGame::Game().LoadRace(selectedMap); }break; + case QUIT:{ + HamsterGame::Game().QuitGame(); + }break; } + if(menuButtons.size()>0)selectedButton=0; } void Menu::DrawTransition(HamsterGame&game){ if(currentTransition==FADE_OUT){ @@ -160,6 +208,19 @@ void Menu::DrawTransition(HamsterGame&game){ void Menu::Draw(HamsterGame&game,const MenuType menu,const vi2d pos){ game.Clear(BLANK); + const auto DrawButtons=[this,&game](const vf2d&offset){ + for(int i{0};const Button&b:menuButtons){ + if(selectedButton.has_value())b.Draw(game,oldLayerPos+game.SCREEN_FRAME.pos,menuButtons[selectedButton.value()]); + else b.Draw(game,oldLayerPos+game.SCREEN_FRAME.pos); + if(selectedButton.has_value())b.Draw(game,oldLayerPos+game.SCREEN_FRAME.pos,menuButtons[selectedButton.value()]); + else b.Draw(game,oldLayerPos+game.SCREEN_FRAME.pos); + } + for(int i{0};const Button&b:newMenuButtons){ + if(selectedButton.has_value())b.Draw(game,newLayerPos+game.SCREEN_FRAME.pos,menuButtons[selectedButton.value()]); + else b.Draw(game,newLayerPos+game.SCREEN_FRAME.pos); + } + }; + switch(menu){ case TITLE_SCREEN:{ game.FillRectDecal(pos,game.SCREEN_FRAME.size,{111,150,255}); @@ -172,8 +233,27 @@ void Menu::Draw(HamsterGame&game,const MenuType menu,const vi2d pos){ case MAIN_MENU:{ game.DrawPartialDecal(vi2d{pos},game.SCREEN_FRAME.size,game.GetGFX("background1.png").Decal(),vf2d{}+int(game.GetRuntime()*4),game.SCREEN_FRAME.size); game.DrawRotatedDecal(pos,game.GetGFX("button.png").Decal(),0.f,game.GetGFX("button.png").Sprite()->Size()/2); + DrawButtons(pos); + game.border.Draw(); + }break; + case GRAND_PRIX:{ + game.DrawPartialDecal(vi2d{pos},game.SCREEN_FRAME.size,game.GetGFX("background5.png").Decal(),vf2d{}+int(game.GetRuntime()*4),game.SCREEN_FRAME.size); + DrawButtons(pos); + game.border.Draw(); + }break; + case SINGLE_RACE:{ + game.DrawPartialDecal(vi2d{pos},game.SCREEN_FRAME.size,game.GetGFX("background4.png").Decal(),vf2d{}+int(game.GetRuntime()*4),game.SCREEN_FRAME.size); + DrawButtons(pos); + game.border.Draw(); + }break; + case OPTIONS:{ + game.DrawPartialDecal(vi2d{pos},game.SCREEN_FRAME.size,game.GetGFX("background2.png").Decal(),vf2d{}+int(game.GetRuntime()*4),game.SCREEN_FRAME.size); + DrawButtons(pos); game.border.Draw(); }break; + case QUIT:{ + game.DrawPartialDecal(vi2d{pos},game.SCREEN_FRAME.size,game.GetGFX("background3.png").Decal(),vf2d{}+int(game.GetRuntime()*4),game.SCREEN_FRAME.size); + }break; case GAMEPLAY:{ game.DrawGame(); }break; @@ -214,12 +294,22 @@ void Menu::UpdateLoadingProgress(const float pctLoaded){ loadingPct=pctLoaded; } -Menu::Button::Button(const vf2d pos,std::string buttonText,Renderable&buttonImg,std::functiononClick) -:pos(pos),buttonText(buttonText),buttonImg(buttonImg),onClick(onClick){} +Menu::Button::Button(const vf2d pos,const std::string&buttonText,const std::string&buttonImg,const std::string&highlightButtonImg,const Pixel textCol,const Pixel highlightTextCol,const std::functiononClick) +:pos(pos),buttonText(buttonText),buttonImg(buttonImg),highlightButtonImg(highlightButtonImg),onClick(onClick),textCol(textCol),highlightTextCol(highlightTextCol){} -void Menu::Button::Update(const float fElapsedTime){ - +const bool Menu::Button::IsHovered(const vf2d&offset)const{ + return geom2d::overlaps(HamsterGame::Game().GetMousePos(),geom2d::rect(pos-HamsterGame::GetGFX(buttonImg).Sprite()->Size()/2+offset,HamsterGame::GetGFX(buttonImg).Sprite()->Size())); } -void Menu::Button::Draw(HamsterGame&game){ - +void Menu::Button::Draw(HamsterGame&game,const vf2d&offset,std::optional>selectedButton)const{ + if(selectedButton.has_value()&&&selectedButton.value().get()==this){ + game.DrawRotatedDecal(pos+offset,game.GetGFX(highlightButtonImg).Decal(),0.f,game.GetGFX(highlightButtonImg).Sprite()->Size()/2); + game.DrawRotatedStringPropDecal(pos+offset,buttonText,0.f,game.GetTextSizeProp(buttonText)/2,highlightTextCol); + }else{ + game.DrawRotatedDecal(pos+offset,game.GetGFX(buttonImg).Decal(),0.f,game.GetGFX(buttonImg).Sprite()->Size()/2); + game.DrawRotatedStringPropDecal(pos+offset,buttonText,0.f,game.GetTextSizeProp(buttonText)/2,textCol); + } +} + +void Menu::Button::OnClick(){ + onClick(); } \ No newline at end of file diff --git a/src/Menu.h b/src/Menu.h index f4a8f0c..bfd17e1 100644 --- a/src/Menu.h +++ b/src/Menu.h @@ -45,12 +45,16 @@ class Menu{ class Button{ std::string buttonText; vf2d pos; - Renderable&buttonImg; + std::string buttonImg; + std::string highlightButtonImg; + Pixel textCol; + Pixel highlightTextCol; std::functiononClick; public: - Button(const vf2d pos,std::string buttonText,Renderable&buttonImg,std::functiononClick={}); - void Update(const float fElapsedTime); - void Draw(HamsterGame&game); + Button(const vf2d pos,const std::string&buttonText,const std::string&buttonImg,const std::string&highlightButtonImg,const Pixel textCol,const Pixel highlightTextCol,const std::functiononClick={}); + const bool IsHovered(const vf2d&offset)const; + void OnClick(); + void Draw(HamsterGame&game,const vf2d&pos,std::optional>selectedButton={})const; }; enum MenuType{ INITIALIZE, @@ -64,6 +68,7 @@ class Menu{ AFTER_RACE_MENU, PAUSE, LOADING, + QUIT, }; enum TransitionType{ SHIFT_LEFT, @@ -81,7 +86,7 @@ class Menu{ MenuType currentMenu{INITIALIZE}; MenuType nextMenu{TITLE_SCREEN}; float menuTimer{}; - const float MENU_TRANSITION_REFRESH_RATE{0.15f}; + const float MENU_TRANSITION_REFRESH_RATE{0.1f}; float menuTransitionRefreshTimer{MENU_TRANSITION_REFRESH_RATE}; float originalMenuTimer{}; vi2d oldLayerPos{}; @@ -90,12 +95,14 @@ class Menu{ bool loading{false}; float loadingPct{0.f}; std::vector