-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMenuScreen.ixx
277 lines (242 loc) · 8.82 KB
/
MenuScreen.ixx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/*
* THERE IS NO ABSTRACT SCREEN. Each Screen object is a VARIATION of each other, but they will NEVER be used interchangably. There's no benefit to that.
*/
/*
* NEXT:
* -- Make Buttons responsive (on hover)
* -- Make window size adjustable
* -- Each Screen will need to capture resize window event from the queue in the loop, and then resize.
* -- Make "New Game" open MAP screen
* -- MAP screen has three buttons (vertical): OTHER MAP, MANU, and BATTLE
* -- Make BATTLE screen with two buttons: BACK TO MAP and MENU
* -- Make "About" open a panel with text.
* -- Make "Settings" open a new menu. (will there really be settings? No... maybe delete!)
* -- Make "Load Game" load different Menu (unless there will only be one game?) (leave alone for now actually)
*/
module;
export module MenuScreen;
import "include/json.hpp";
import "SDL.h";
import "SDL_image.h";
import <stdio.h>;
import <string>;
import <iostream>;
import "SDL_ttf.h";
import <vector>;
import <cstdlib>;
import <time.h>;
import <unordered_map>;
import TypeStorage;
import GameState;
import Resources;
import UI;
using namespace std;
export class MenuScreen {
public:
/* constructor */
MenuScreen() {
UI& ui = UI::getInstance();
screenType = ScreenType::Menu;
screenToLoadStruct = ScreenStruct(ScreenType::NoScreen, -1);
getBackgroundTexture(ui);
createTitleTexture(ui);
skyBG = SkyAndCloudsBackground(true);
}
/* Destructor */
~MenuScreen() {
SDL_DestroyTexture(bgTexture);
SDL_DestroyTexture(titleTexture);
}
void setParentStruct(ScreenStruct incomingParentStruct) {
screenToLoadStruct = incomingParentStruct;
}
ScreenStruct getParentStruct() { return screenToLoadStruct; }
void getBackgroundTexture(UI& ui);
void createTitleTexture(UI& ui);
void run();
private:
ScreenType screenType;
ScreenStruct screenToLoadStruct;
SDL_Texture* bgTexture = NULL;
SDL_Rect bgSourceRect;
SDL_Rect bgDestinationRect;
SDL_Texture* titleTexture;
SDL_Rect titleRect;
void handleEvent(SDL_Event &e, bool& running, Panel& menuPanel, Panel& settingsPanel, GameState& gameState);
void checkMouseLocation(SDL_Event& e, Panel& menuPanel, Panel& settingsPanel);
void rebuildDisplay(Panel& menuPanel, Panel& settingsPanel);
void draw(UI& ui, Panel& menuPanel, Panel& settingsPanel);
SkyAndCloudsBackground skyBG;
};
/* The main function of the class. Contains the game loop. */
void MenuScreen::run() {
cout << "Menu Screen loaded\n";
// Get reference to UI singleton for the loop
UI& ui = UI::getInstance();
GameState& gameState = GameState::getInstance();
Panel menuPanel = ui.createMainMenuPanel();
Panel settingsPanel = ui.createSettingsPanel();
menuPanel.setShow(true);
settingsPanel.setShow(false);
/* Timeout data */
const int TARGET_FPS = 120;
const int FRAME_DELAY = 1200 / TARGET_FPS; // milliseconds per frame
Uint32 frameStartTime; // Tick count when this particular frame began
int frameTimeElapsed; // how much time has elapsed during this frame
/* loop and event control */
SDL_Event e;
bool running = true;
while (running) {
/* Get the total running time(tick count) at the beginning of the frame, for the frame timeout at the end */
frameStartTime = SDL_GetTicks();
/* Check for events in queue, and handle them(really just checking for X close now */
while (SDL_PollEvent(&e) != 0) {
handleEvent(e, running, menuPanel, settingsPanel, gameState);
}
/* check mouse location in every frame (so buttons stay "hovered" after click */
checkMouseLocation(e, menuPanel, settingsPanel);
draw(ui, menuPanel, settingsPanel);
/* Delay so the app doesn't just crash */
frameTimeElapsed = SDL_GetTicks() - frameStartTime; // Calculate how long the frame took to process
/* Delay loop */
if (frameTimeElapsed < FRAME_DELAY) {
SDL_Delay(FRAME_DELAY - frameTimeElapsed);
}
}
/* set the next screen to load */
gameState.setScreenStruct(screenToLoadStruct);
}
/*
* All data has been updated. Time to draw a representation of the current state of things.
* We draw one panel at a time.
*
* TODO: There is a problem here. We should NOT be drawing the background twice.
* CLEAN THIS UP.
*
* Send in a vector of panels.
*/
void MenuScreen::draw(UI& ui, Panel& menuPanel, Panel& settingsPanel) {
/* draw panel(make this a function of the UI object which takes a panel as a parameter) */
SDL_SetRenderDrawColor(ui.getMainRenderer(), 14, 14, 14, 1);
SDL_RenderClear(ui.getMainRenderer());
/* print the BG image) */
//SDL_RenderCopyEx(ui.getMainRenderer(), bgTexture, &bgSourceRect, &bgDestinationRect, 0, NULL, SDL_FLIP_NONE);
skyBG.draw();
/* draw the actual panels */
settingsPanel.draw(ui);
menuPanel.draw(ui);
/* draw the logo */
SDL_RenderCopyEx(ui.getMainRenderer(), titleTexture, NULL, &titleRect, 0, NULL, SDL_FLIP_NONE);
SDL_RenderPresent(ui.getMainRenderer()); /* update window */
}
void MenuScreen::getBackgroundTexture(UI& ui) {
int windowHeight, windowWidth;
SDL_GetWindowSize(ui.getMainWindow(), &windowWidth, &windowHeight);
bgSourceRect = { 0, 0, windowWidth, windowHeight };
bgDestinationRect = { 0, 0, windowWidth, windowHeight };
bgTexture = ui.createBackgroundTexture();
}
/* Create the texture with the name of the game */
void MenuScreen::createTitleTexture(UI& ui) {
Resources& resources = Resources::getInstance();
auto [incomingTitleTexture, incomingTitleRect] = ui.createTitleTexture(resources.getTitle());
titleTexture = incomingTitleTexture;
titleRect = incomingTitleRect;
}
/* Screen has been resized. Rebuild! */
void MenuScreen::rebuildDisplay(Panel& menuPanel, Panel& settingsPanel) {
UI& ui = UI::getInstance();
getBackgroundTexture(ui);
createTitleTexture(ui);
ui.rebuildSettingsPanel(settingsPanel);
ui.rebuildMainMenuPanel(menuPanel);
}
/* Process user input */
void MenuScreen::handleEvent(SDL_Event& e, bool& running, Panel& menuPanel, Panel& settingsPanel, GameState& gameState) {
/* User pressed X to close */
if (e.type == SDL_QUIT) { running = false; }
else {
// user clicked
if (e.type == SDL_MOUSEBUTTONDOWN) {
cout << "user clicked mouse\n";
// These events might change the value of screenToLoad
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
if (menuPanel.getShow() && menuPanel.isInPanel(mouseX, mouseY)) {
// panel has a function to return which ButtonOption was clicked, and an ID (in the ButtonClickStruct).
ButtonClickStruct clickStruct = menuPanel.checkButtonClick(mouseX, mouseY);
// see what button might have been clicked:
switch (clickStruct.buttonOption) {
case ButtonOption::About:
screenToLoadStruct.screenType = ScreenType::CharacterCreation;
running = false;
cout << "ABOUT\n";
break;
case ButtonOption::NoOption:
cout << "NO OPTION\n";
break;
case ButtonOption::NewGame:
screenToLoadStruct.screenType = ScreenType::Map;
running = false;
cout << "NEW GAME\n";
break;
case ButtonOption::LoadGame:
screenToLoadStruct.screenType = ScreenType::Battle;
running = false;
cout << "LOAD GAME (currently battle screen)\n";
break;
case ButtonOption::Settings:
// switch to other panel
settingsPanel.setShow(true);
menuPanel.setShow(false);
cout << "SETTINGS\n";
break;
case ButtonOption::Exit:
gameState.setScreenType(ScreenType::NoScreen);
running = false;
break;
default:
cout << "ERROR\n";
}
} else if (settingsPanel.getShow() && settingsPanel.isInPanel(mouseX, mouseY)) {
// panel has a function to return which ButtonOption was clicked, and an ID (in the ButtonClickStruct).
ButtonClickStruct clickStruct = settingsPanel.checkButtonClick(mouseX, mouseY);
UI& ui = UI::getInstance();
// see what button might have been clicked:
switch (clickStruct.buttonOption) {
case ButtonOption::Mobile:
ui.resizeWindow(WindowResType::Mobile);
rebuildDisplay(menuPanel, settingsPanel);
break;
case ButtonOption::Tablet:
ui.resizeWindow(WindowResType::Tablet);
rebuildDisplay(menuPanel, settingsPanel);
break;
case ButtonOption::Desktop:
ui.resizeWindow(WindowResType::Desktop);
rebuildDisplay(menuPanel, settingsPanel);
break;
case ButtonOption::Fullscreen:
ui.resizeWindow(WindowResType::Fullscreen);
rebuildDisplay(menuPanel, settingsPanel);
break;
case ButtonOption::Back:
// switch to other panel
settingsPanel.setShow(false);
menuPanel.setShow(true);
break;
default:
cout << "ERROR\n";
}
}
}
}
}
void MenuScreen::checkMouseLocation(SDL_Event& e, Panel& menuPanel, Panel& settingsPanel) {
/* check for mouse over(for button hover) */
int mouseX, mouseY;
SDL_GetMouseState(&mouseX, &mouseY);
/* send the x and y to the panel and its buttons to change the color */
if (menuPanel.getShow()) { menuPanel.checkMouseOver(mouseX, mouseY); }
if (settingsPanel.getShow()) { settingsPanel.checkMouseOver(mouseX, mouseY); }
}