summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--res/sfx/menu_deselect.wavbin0 -> 29480 bytes
-rw-r--r--src/menu.cpp23
-rw-r--r--src/menu.h19
-rw-r--r--src/menu_system.cpp95
-rw-r--r--src/menu_system.h24
-rw-r--r--src/renderer.cpp26
-rw-r--r--src/renderer.h3
7 files changed, 137 insertions, 53 deletions
diff --git a/res/sfx/menu_deselect.wav b/res/sfx/menu_deselect.wav new file mode 100644 index 0000000..800f84f --- /dev/null +++ b/res/sfx/menu_deselect.wav
Binary files differ
diff --git a/src/menu.cpp b/src/menu.cpp index 4da4574..cfb0dd6 100644 --- a/src/menu.cpp +++ b/src/menu.cpp
@@ -1,12 +1,25 @@
1#include "menu.h" 1#include "menu.h"
2 2
3std::vector<MenuItem> CreateMenu(const std::vector<MenuBuilder>& builders) { 3Menu::Menu(const std::vector<MenuBuilder>& builders) {
4 std::vector<MenuItem> result; 4 items_.reserve(builders.size());
5 result.reserve(builders.size());
6 5
7 for (const MenuBuilder& builder : builders) { 6 for (const MenuBuilder& builder : builders) {
8 result.push_back(builder.Build()); 7 items_.push_back(builder.Build());
9 } 8 }
9}
10
11void Menu::moveCursorUp() {
12 cursor_--;
10 13
11 return result; 14 if (cursor_ < 0) {
15 cursor_ = items_.size() - 1;
16 }
17}
18
19void Menu::moveCursorDown() {
20 cursor_++;
21
22 if (cursor_ >= items_.size()) {
23 cursor_ = 0;
24 }
12} 25}
diff --git a/src/menu.h b/src/menu.h index 528f8c8..67c75c0 100644 --- a/src/menu.h +++ b/src/menu.h
@@ -48,6 +48,23 @@ private:
48 MenuItem result_; 48 MenuItem result_;
49}; 49};
50 50
51std::vector<MenuItem> CreateMenu(const std::vector<MenuBuilder>& builders); 51class Menu {
52public:
53
54 explicit Menu(const std::vector<MenuBuilder>& builders);
55
56 const std::vector<MenuItem>& getItems() const { return items_; }
57
58 int getCursorPosition() const { return cursor_; }
59
60 void moveCursorUp();
61
62 void moveCursorDown();
63
64private:
65
66 std::vector<MenuItem> items_;
67 int cursor_ = 0;
68};
52 69
53#endif /* end of include guard: MENU_H_3F6E62B3 */ 70#endif /* end of include guard: MENU_H_3F6E62B3 */
diff --git a/src/menu_system.cpp b/src/menu_system.cpp index 7631e4d..7ac8af5 100644 --- a/src/menu_system.cpp +++ b/src/menu_system.cpp
@@ -4,10 +4,12 @@
4 4
5void MenuSystem::tick(double dt) { 5void MenuSystem::tick(double dt) {
6 pauseAnimation_.tick(dt); 6 pauseAnimation_.tick(dt);
7 menuChangeAnimation_.tick(dt);
7 8
8 if (openState_ == OpenState::Animating && pauseAnimation_.isComplete()) { 9 if (openState_ == OpenState::Animating && pauseAnimation_.isComplete()) {
9 if (pauseAnimation_.getProgress() == 0.0) { 10 if (pauseAnimation_.getProgress() == 0.0) {
10 openState_ = OpenState::Closed; 11 openState_ = OpenState::Closed;
12 menus_.clear();
11 13
12 game_.unpauseGameplay(); 14 game_.unpauseGameplay();
13 game_.getMixer().unpauseSounds(); 15 game_.getMixer().unpauseSounds();
@@ -15,20 +17,28 @@ void MenuSystem::tick(double dt) {
15 openState_ = OpenState::Open; 17 openState_ = OpenState::Open;
16 } 18 }
17 } else if (openState_ == OpenState::Open) { 19 } else if (openState_ == OpenState::Open) {
18 cursorBobTimer_.accumulate(dt); 20 if (!isMenuChanging_) {
19 while (cursorBobTimer_.step()) { 21 cursorBobTimer_.accumulate(dt);
20 if (cursorBobDown_) { 22 while (cursorBobTimer_.step()) {
21 cursorBob_++; 23 if (cursorBobDown_) {
22 24 cursorBob_++;
23 if (cursorBob_ >= 4) { 25
24 cursorBobDown_ = false; 26 if (cursorBob_ >= 4) {
27 cursorBobDown_ = false;
28 }
29 } else {
30 cursorBob_--;
31
32 if (cursorBob_ <= 0) {
33 cursorBobDown_ = true;
34 }
25 } 35 }
26 } else { 36 }
27 cursorBob_--; 37 } else if (menuChangeAnimation_.isComplete()) {
38 isMenuChanging_ = false;
28 39
29 if (cursorBob_ <= 0) { 40 if (menuChangeAnimation_.getProgress() == 0.0) {
30 cursorBobDown_ = true; 41 menus_.pop_back();
31 }
32 } 42 }
33 } 43 }
34 } 44 }
@@ -41,7 +51,16 @@ void MenuSystem::openPauseMenu() {
41 game_.pauseGameplay(); 51 game_.pauseGameplay();
42 52
43 std::vector<MenuBuilder> builders = { 53 std::vector<MenuBuilder> builders = {
44 MenuBuilder().Command("Settings"), 54 MenuBuilder().Command("Settings")
55 .ActivationFunction([this] (Game&) {
56 openSubmenu(Menu({
57 MenuBuilder().Command("Back")
58 .ActivationFunction([this] (Game& game) {
59 closePauseMenu();
60 })
61 .SkipSoundEffect()
62 }));
63 }),
45 MenuBuilder().Command("Resume Game") 64 MenuBuilder().Command("Resume Game")
46 .ActivationFunction([] (Game& game) { 65 .ActivationFunction([] (Game& game) {
47 game.getSystem<MenuSystem>().closePauseMenu(); 66 game.getSystem<MenuSystem>().closePauseMenu();
@@ -61,29 +80,32 @@ void MenuSystem::openPauseMenu() {
61 })); 80 }));
62 } 81 }
63 82
64 menu_ = CreateMenu(builders); 83 menus_.emplace_back(builders);
65
66 cursor_ = 0;
67 84
68 game_.getMixer().pauseSounds(); 85 game_.getMixer().pauseSounds();
69 game_.getMixer().playSound("../res/sfx/menu_open.wav"); 86 game_.getMixer().playSound("../res/sfx/menu_open.wav");
70} 87}
71 88
72void MenuSystem::closePauseMenu(bool playSfx) { 89void MenuSystem::closePauseMenu(bool playSfx) {
73 pauseAnimation_.start(125, 0.0); 90 if (menus_.size() > 1) {
74 openState_ = OpenState::Animating; 91 isMenuChanging_ = true;
92 menuChangeAnimation_.start(250, 0.0);
93
94 if (playSfx) {
95 game_.getMixer().playSound("../res/sfx/menu_deselect.wav");
96 }
97 } else {
98 pauseAnimation_.start(125, 0.0);
99 openState_ = OpenState::Animating;
75 100
76 if (playSfx) { 101 if (playSfx) {
77 game_.getMixer().playSound("../res/sfx/menu_close.wav"); 102 game_.getMixer().playSound("../res/sfx/menu_close.wav");
103 }
78 } 104 }
79} 105}
80 106
81void MenuSystem::pressedUp() { 107void MenuSystem::pressedUp() {
82 cursor_--; 108 menus_.back().moveCursorUp();
83
84 if (cursor_ < 0) {
85 cursor_ = menu_.size() - 1;
86 }
87 109
88 cursorBob_ = 0; 110 cursorBob_ = 0;
89 cursorBobDown_ = true; 111 cursorBobDown_ = true;
@@ -92,11 +114,7 @@ void MenuSystem::pressedUp() {
92} 114}
93 115
94void MenuSystem::pressedDown() { 116void MenuSystem::pressedDown() {
95 cursor_++; 117 menus_.back().moveCursorDown();
96
97 if (cursor_ >= menu_.size()) {
98 cursor_ = 0;
99 }
100 118
101 cursorBob_ = 0; 119 cursorBob_ = 0;
102 cursorBobDown_ = true; 120 cursorBobDown_ = true;
@@ -105,13 +123,22 @@ void MenuSystem::pressedDown() {
105} 123}
106 124
107void MenuSystem::activateOption() { 125void MenuSystem::activateOption() {
108 if (menu_[cursor_].type == MenuType::Command) { 126 Menu& curMenu = menus_.back();
109 if (menu_[cursor_].playSfx) { 127 const MenuItem& menuItem = curMenu.getItems()[curMenu.getCursorPosition()];
128
129 if (menuItem.type == MenuType::Command) {
130 if (menuItem.playSfx) {
110 game_.getMixer().playSound("../res/sfx/menu_activate.wav"); 131 game_.getMixer().playSound("../res/sfx/menu_activate.wav");
111 } 132 }
112 133
113 if (menu_[cursor_].activationFunction) { 134 if (menuItem.activationFunction) {
114 menu_[cursor_].activationFunction(game_); 135 menuItem.activationFunction(game_);
115 } 136 }
116 } 137 }
117} 138}
139
140void MenuSystem::openSubmenu(Menu submenu) {
141 menus_.push_back(std::move(submenu));
142 isMenuChanging_ = true;
143 menuChangeAnimation_.start(250, 1.0);
144}
diff --git a/src/menu_system.h b/src/menu_system.h index 736d555..c921d0b 100644 --- a/src/menu_system.h +++ b/src/menu_system.h
@@ -1,6 +1,7 @@
1#ifndef MENU_SYSTEM_H_205861EC 1#ifndef MENU_SYSTEM_H_205861EC
2#define MENU_SYSTEM_H_205861EC 2#define MENU_SYSTEM_H_205861EC
3 3
4#include <deque>
4#include <vector> 5#include <vector>
5#include "interpolation.h" 6#include "interpolation.h"
6#include "menu.h" 7#include "menu.h"
@@ -34,16 +35,24 @@ public:
34 35
35 double getPauseAnimationProgress() const { return pauseAnimation_.getProgress(); } 36 double getPauseAnimationProgress() const { return pauseAnimation_.getProgress(); }
36 37
37 bool isMenuOpen() const { return openState_ == OpenState::Open; } 38 bool isMenuOpen() const { return openState_ == OpenState::Open && !isMenuChanging_; }
38 39
39 const std::vector<MenuItem>& getMenu() const { return menu_; } 40 // Only call this if a menu is open.
41 Menu& getMenu() { return menus_.back(); }
40 42
41 int getCursorPosition() const { return cursor_; } 43 // Only call this if a submenu is open.
44 Menu& getParentMenu() { return menus_[menus_.size()-2]; }
42 45
43 int getCursorBob() const { return cursorBob_; } 46 int getCursorBob() const { return cursorBob_; }
44 47
48 double getMenuChangeAnimationProgress() const { return menuChangeAnimation_.getProgress(); }
49
50 bool isMenuChanging() const { return isMenuChanging_; }
51
45private: 52private:
46 53
54 void openSubmenu(Menu submenu);
55
47 enum class OpenState { 56 enum class OpenState {
48 Closed, 57 Closed,
49 Animating, 58 Animating,
@@ -51,13 +60,18 @@ private:
51 }; 60 };
52 61
53 Game& game_; 62 Game& game_;
63
54 Interpolation pauseAnimation_; 64 Interpolation pauseAnimation_;
55 OpenState openState_ = OpenState::Closed; 65 OpenState openState_ = OpenState::Closed;
56 std::vector<MenuItem> menu_; 66
57 int cursor_ = 0; 67 std::deque<Menu> menus_;
68
58 int cursorBob_ = 0; 69 int cursorBob_ = 0;
59 bool cursorBobDown_ = true; 70 bool cursorBobDown_ = true;
60 Timer cursorBobTimer_ { 125 }; 71 Timer cursorBobTimer_ { 125 };
72
73 Interpolation menuChangeAnimation_;
74 bool isMenuChanging_ = false;
61}; 75};
62 76
63#endif /* end of include guard: MENU_SYSTEM_H_205861EC */ 77#endif /* end of include guard: MENU_SYSTEM_H_205861EC */
diff --git a/src/renderer.cpp b/src/renderer.cpp index fc16e20..f7644ca 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp
@@ -3,6 +3,7 @@
3#include "consts.h" 3#include "consts.h"
4#include "game.h" 4#include "game.h"
5#include "map.h" 5#include "map.h"
6#include "menu.h"
6#include "transform_system.h" 7#include "transform_system.h"
7#include "camera_system.h" 8#include "camera_system.h"
8#include "message_system.h" 9#include "message_system.h"
@@ -142,11 +143,22 @@ void Renderer::render(Game& game) {
142 } 143 }
143 144
144 if (menus.getPauseAnimationProgress() > 0.0) { 145 if (menus.getPauseAnimationProgress() > 0.0) {
145 renderMenu(game); 146 renderMenu(game, menus.getMenu());
146 147
147 SDL_SetRenderTarget(ren_.get(), canvas.get()); 148 SDL_SetRenderTarget(ren_.get(), canvas.get());
148 if (menus.getPauseAnimationProgress() == 1.0) { 149 if (menus.getPauseAnimationProgress() == 1.0) {
149 SDL_RenderCopy(ren_.get(), menuTex_.get(), nullptr, nullptr); 150 if (menus.isMenuChanging()) {
151 SDL_Rect dest { static_cast<int>(CANVAS_WIDTH * (1.0 - menus.getMenuChangeAnimationProgress())), 0, CANVAS_WIDTH, CANVAS_HEIGHT };
152 SDL_RenderCopy(ren_.get(), menuTex_.get(), nullptr, &dest);
153
154 renderMenu(game, menus.getParentMenu());
155
156 dest.x -= CANVAS_WIDTH;
157 SDL_SetRenderTarget(ren_.get(), canvas.get());
158 SDL_RenderCopy(ren_.get(), menuTex_.get(), nullptr, &dest);
159 } else {
160 SDL_RenderCopy(ren_.get(), menuTex_.get(), nullptr, nullptr);
161 }
150 } else { 162 } else {
151 int barHeight = CANVAS_HEIGHT / 2 * menus.getPauseAnimationProgress(); 163 int barHeight = CANVAS_HEIGHT / 2 * menus.getPauseAnimationProgress();
152 SDL_Rect topHalf { 0, 0, CANVAS_WIDTH, barHeight }; 164 SDL_Rect topHalf { 0, 0, CANVAS_WIDTH, barHeight };
@@ -536,7 +548,7 @@ void Renderer::renderGame(Game& game) {
536 } 548 }
537} 549}
538 550
539void Renderer::renderMenu(Game& game) { 551void Renderer::renderMenu(Game& game, const Menu& menu) {
540 auto& menus = game.getSystem<MenuSystem>(); 552 auto& menus = game.getSystem<MenuSystem>();
541 553
542 if (!menuTex_) { 554 if (!menuTex_) {
@@ -558,11 +570,11 @@ void Renderer::renderMenu(Game& game) {
558 SDL_RenderFillRect(ren_.get(), nullptr); 570 SDL_RenderFillRect(ren_.get(), nullptr);
559 571
560 const int lineHeight = 16; 572 const int lineHeight = 16;
561 int totalHeight = menus.getMenu().size() * lineHeight; 573 int totalHeight = menu.getItems().size() * lineHeight;
562 std::vector<vec2i> positions; 574 std::vector<vec2i> positions;
563 575
564 int index = 0; 576 int index = 0;
565 for (const MenuItem& menuItem : menus.getMenu()) { 577 for (const MenuItem& menuItem : menu.getItems()) {
566 switch (menuItem.type) { 578 switch (menuItem.type) {
567 case MenuType::Command: { 579 case MenuType::Command: {
568 MessageCache output; 580 MessageCache output;
@@ -589,8 +601,8 @@ void Renderer::renderMenu(Game& game) {
589 601
590 int cursorTexId = loadImageFromFile("../res/feather_pen.png"); 602 int cursorTexId = loadImageFromFile("../res/feather_pen.png");
591 const SDL_Rect cursorDest { 603 const SDL_Rect cursorDest {
592 positions[menus.getCursorPosition()].x() - 2 - 16 - menus.getCursorBob(), 604 positions[menu.getCursorPosition()].x() - 2 - 16 - menus.getCursorBob(),
593 positions[menus.getCursorPosition()].y() - 8 - menus.getCursorBob(), 605 positions[menu.getCursorPosition()].y() - 8 - menus.getCursorBob(),
594 16, 606 16,
595 16 }; 607 16 };
596 SDL_RenderCopy(ren_.get(), textures_.at(cursorTexId).get(), nullptr, &cursorDest); 608 SDL_RenderCopy(ren_.get(), textures_.at(cursorTexId).get(), nullptr, &cursorDest);
diff --git a/src/renderer.h b/src/renderer.h index 75bd9fe..82d34a5 100644 --- a/src/renderer.h +++ b/src/renderer.h
@@ -12,6 +12,7 @@
12class Game; 12class Game;
13class Map; 13class Map;
14class Sprite; 14class Sprite;
15class Menu;
15 16
16class sdl_error : public std::logic_error { 17class sdl_error : public std::logic_error {
17public: 18public:
@@ -135,7 +136,7 @@ private:
135 std::map<std::string, int> filenameToTexId_; 136 std::map<std::string, int> filenameToTexId_;
136 137
137 // Menu rendering 138 // Menu rendering
138 void renderMenu(Game& game); 139 void renderMenu(Game& game, const Menu& menu);
139 140
140 texture_ptr menuTex_; 141 texture_ptr menuTex_;
141 142