-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathState_Game.cpp
More file actions
334 lines (310 loc) · 12.3 KB
/
State_Game.cpp
File metadata and controls
334 lines (310 loc) · 12.3 KB
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#include "State_Game.h"
#include "StateManager.h"
#include "Comp_Position.h"
#include "Comp_Movement.h"
#include "Comp_Invader.h"
#include "LevelManager.h"
#include "Trigger.h"
#include "Utils.h"
State_Game::State_Game(StateManager* stateManager) :
State(stateManager),
m_levelManager(stateManager->getContext()->m_actorManager),
m_hudUpdateTimer(0),
m_newGame(true),
m_fps(0),
m_soundOn(true),
m_musicOn(true),
m_showNewScoreTimer(0),
m_showScoreAlpha(0)
{
}
void State_Game::update(const float& deltaTime)
{
if (m_levelManager.getInvaderCount() <= 0)
loadNextLevel();
m_fps = static_cast<unsigned int>(1.f / deltaTime);
// handle player movement input
handlePlayerPosition();
// game update
m_stateManager->getContext()->m_systemManager->update(deltaTime);
// HUD update
updateHUD(deltaTime);
// if player dead, prepare to switch to Game Over screen
switch (m_levelManager.getState())
{
case LevelState::PlayerAlive:
break;
case LevelState::PlayerDestroyed:
gameOverScreen();
break;
case LevelState::PlayerInvaded:
gameOverScreen();
break;
}
}
void State_Game::draw()
{
// draw game
auto* window = m_stateManager->getContext()->m_windowManager->getRenderWindow();
window->setView(m_gameView);
window->draw(m_background);
m_stateManager->getContext()->m_systemManager->draw(m_stateManager->getContext()->m_windowManager);
// draw HUD
window->setView(m_view);
window->draw(m_scoreText);
window->draw(m_levelText);
window->draw(m_killsText);
#ifdef DEBUG
window->draw(m_fpsText);
#endif
window->draw(m_helpText);
window->draw(m_soundText);
window->draw(m_musicText);
// show new score if needed
if (m_showingNewScore)
window->draw(m_newScoreText);
// draw player lives
float iconWidth = m_playerIcon.getGlobalBounds().width;
for (int i = 0; i < m_levelManager.getPlayerLives(); ++i)
{
m_playerIcon.setPosition(m_playerIconPosition.x + i * iconWidth - 3 * iconWidth, m_playerIconPosition.y);
window->draw(m_playerIcon);
}
// draw help panel if enabled
if (m_showHelp)
{
window->draw(m_helpPanel);
window->draw(m_helpPanelTitle);
window->draw(m_helpPanelText);
}
}
void State_Game::onCreate()
{
sf::Vector2u windowSize = m_stateManager->getContext()->m_windowManager->getRenderWindow()->getSize();
m_view.setSize(static_cast<float>(windowSize.x), static_cast<float>(windowSize.y));
m_view.setCenter(static_cast<float>(windowSize.x) / 2, static_cast<float>(windowSize.y) / 2);
m_view.setViewport(sf::FloatRect(0, 0, 1, 1));
m_gameView.setViewport(sf::FloatRect(0.15f, 0, 0.7f, 1));
m_stateManager->getContext()->m_systemManager->setLevelManager(&m_levelManager);
m_levelManager.setViewSpace(getGameViewSpace());
initializeHUD();
setupHelpPanel();
// load music
m_stateManager->getContext()->m_soundManager->loadSoundProfile("assets/profiles/soundProfiles/game_state.sound");
// play music
m_stateManager->getContext()->m_soundManager->playMusic("game_music");
setSound(true);
setMusic(false);
// set player icon position to upper right of screen
m_playerIconPosition = sf::Vector2f(
m_view.getCenter().x + m_view.getSize().x / 2 - m_hudPadding.x,
m_view.getCenter().y - m_view.getSize().y / 2 + m_hudPadding.y
);
}
void State_Game::activate()
{
// add callbacks
m_stateManager->getContext()->m_controller->m_onPause.addCallback("Game_onPause", std::bind(&StateManager::switchTo, m_stateManager, StateType::Paused));
m_stateManager->getContext()->m_controller->m_onShoot.addCallback("Game_onShoot", std::bind(&State_Game::onPlayerShoot, this));
m_stateManager->getContext()->m_controller->m_onToggleHelp.addCallback("Game_onToggleHelp", std::bind(&State_Game::onToggleHelp, this));
m_stateManager->getContext()->m_controller->m_onToggleSound.addCallback("Game_onToggleSound", std::bind(&State_Game::onToggleSound, this));
m_stateManager->getContext()->m_controller->m_onToggleMusic.addCallback("Game_onToggleMusic", std::bind(&State_Game::onToggleMusic, this));
m_levelManager.m_updateScore.addCallback("Game_onUpdateScore", std::bind(&State_Game::showNewScore, this, std::placeholders::_1));
// start new game if one is required
if (m_newGame)
newGame();
}
void State_Game::deactivate()
{
m_stateManager->getContext()->m_controller->m_onPause.removeCallback("Game_onPause");
m_stateManager->getContext()->m_controller->m_onShoot.removeCallback("Game_onShoot");
m_stateManager->getContext()->m_controller->m_onToggleHelp.removeCallback("Game_onToggleHelp");
m_stateManager->getContext()->m_controller->m_onToggleSound.removeCallback("Game_onToggleSound");
m_stateManager->getContext()->m_controller->m_onToggleMusic.removeCallback("Game_onToggleMusic");
}
void State_Game::loadNextLevel()
{
// increase level
m_levelManager++;
// reset invader count
m_levelManager.resetInvaderCount();
// enable (or re-enable) all actors
//for (auto& invaderId : m_levelManager.getInvaderIds())
// m_stateManager->getContext()->m_actorManager->enableActor(invaderId);
auto invaderSys = m_stateManager->getContext()->m_systemManager->getSystem<Sys_InvaderControl>(SystemType::InvaderControl);
invaderSys->queueInvaders(m_levelManager.getInvaderIds());
// start (or re-start) all systems
m_stateManager->getContext()->m_systemManager->start();
}
void State_Game::handlePlayerPosition()
{
// get render window
const auto& window = *m_stateManager->getContext()->m_windowManager->getRenderWindow();
// get mouse position relative to window
sf::Vector2i mousePos = sf::Mouse::getPosition(window);
// clamp mouse position to view space
if (mousePos.x < 0) mousePos.x = 0;
else if (mousePos.x > static_cast<int>(window.getSize().x)) mousePos.x = static_cast<int>(window.getSize().x);
sf::Mouse::setPosition(mousePos, window);
// calculate mouse position relative to window
const auto& mousePosInWindow = mousePos.x / static_cast<float>(window.getSize().x);
// calculate player position relative to view space
const auto& playerPosInView = m_levelManager.getViewSpace().getPosition().x + m_controlMargin + (m_levelManager.getViewSpace().getSize().x - 2 * m_controlMargin) * mousePosInWindow;
// set player target to its position
unsigned int playerId = m_levelManager.getPlayerId();
// get player target component
const auto& actor = m_stateManager->getContext()->m_actorManager->getActor(playerId);
const auto& targetComp = actor->getComponent<Comp_Target>(ComponentType::Target);
// set player target position
targetComp->setTarget(sf::Vector2f(playerPosInView, m_levelManager.getPlayerSpawnPoint().y));
}
void State_Game::onPlayerShoot()
{
m_stateManager->getContext()->m_systemManager->addEvent(m_levelManager.getPlayerId(), (EventId)ActorEventType::Shoot);
}
void State_Game::onToggleHelp()
{
m_showHelp = !m_showHelp;
}
void State_Game::setSound(bool soundOn)
{
m_soundOn = soundOn;
auto soundSys = m_stateManager->getContext()->m_systemManager->getSystem<Sys_Sound>(SystemType::Sound);
soundSys->setSound(m_soundOn);
m_soundText.setFillColor(m_soundOn ? APP_COLOR : APP_COLOR_TRANSP);
}
void State_Game::setMusic(bool musicOn)
{
m_musicOn = musicOn;
m_stateManager->getContext()->m_soundManager->setMusic(m_musicOn ? 100.f : 0.f);
m_musicText.setFillColor(m_musicOn ? APP_COLOR : APP_COLOR_TRANSP);
}
void State_Game::onToggleSound()
{
setSound(!m_soundOn);
}
void State_Game::onToggleMusic()
{
setMusic(!m_musicOn);
}
void State_Game::gameOverScreen()
{
m_newGame = true;
m_stateManager->remove(StateType::Paused);
m_stateManager->switchTo(StateType::GameOver);
m_levelManager.purge();
}
/// <summary>
/// Purges all actors and resets the game state.
/// </summary>
void State_Game::newGame()
{
m_newGame = false;
m_stateManager->getContext()->m_actorManager->purge();
m_levelManager.newGame();
m_controlMargin = m_stateManager->getContext()->m_actorManager->getActor(m_levelManager.getPlayerId())->getComponent<Comp_Collision>(ComponentType::Collision)->getAABB().width / 2.f;
m_stateManager->getContext()->m_actorManager->enableActor(m_levelManager.getPlayerId());
// set player icon to use in HUD
const auto& playerSprite = m_stateManager->getContext()->m_actorManager->getActor(m_levelManager.getPlayerId())->getComponent<Comp_SpriteSheet>(ComponentType::SpriteSheet);
m_playerIcon = *playerSprite->getSpriteSheet()->getSprite();
}
void State_Game::updateHUD(const float& deltaTime)
{
m_hudUpdateTimer -= deltaTime;
// if enough time has passed, update the score
if (m_hudUpdateTimer < 0)
{
m_scoreText.setString("Score:\n" + std::to_string(m_levelManager.getScore()));
m_levelText.setString("Level:\n" + std::to_string(m_levelManager.getLevel()));
m_killsText.setString("Kills:\n" + std::to_string(m_levelManager.getKills()));
m_fpsText.setString("FPS:\n" + std::to_string(m_fps));
m_hudUpdateTimer = m_hudUpdateInterval;
}
// if new score needs to be shown
if (m_showingNewScore)
{
m_showNewScoreTimer += deltaTime;
if (m_showNewScoreTimer < m_showNewScoreDuration)
{
const auto pos = sf::Vector2f(m_hudPadding.x + m_fontSize, m_hudPadding.x);
const float ratio = m_showNewScoreTimer / m_showNewScoreDuration;
m_showScoreAlpha = ratio < 0.5f ? 1.f : 1.f - ratio;
sf::Color color = APP_COLOR;
color.a = static_cast<sf::Uint8>(m_showScoreAlpha * 255);
m_newScoreText.setFillColor(color);
const auto new_pos = pos + sf::Vector2f(0, m_newScoreOffset * ratio);
m_newScoreText.setPosition(new_pos);
}
else
m_showingNewScore = false;
}
}
void State_Game::initializeHUD()
{
setWindowOutline();
initializeHUDText(m_scoreText);
m_scoreText.setPosition(m_hudPadding.x, 0);
initializeHUDText(m_newScoreText);
initializeHUDText(m_levelText);
m_levelText.setPosition(m_hudPadding.x, m_hudPadding.y + m_fontSize);
initializeHUDText(m_killsText);
m_killsText.setPosition(m_hudPadding.x, 2 * (m_hudPadding.y + m_fontSize));
initializeHUDText(m_fpsText);
m_fpsText.setPosition(m_hudPadding.x, 3 * (m_hudPadding.y + m_fontSize));
initializeHUDText(m_helpText);
m_helpText.setPosition(m_hudPadding.x, m_levelManager.getViewSpace().height - m_fontSize);
m_helpText.setString("HELP (H)");
initializeHUDText(m_soundText);
m_soundText.setString("SOUND (S)");
m_soundText.setPosition(m_view.getSize().x - m_hudPadding.x - 200, m_levelManager.getViewSpace().height - 2 * m_fontSize);
initializeHUDText(m_musicText);
m_musicText.setString("MUSIC (M)");
m_musicText.setPosition(m_view.getSize().x - m_hudPadding.x - 200, m_levelManager.getViewSpace().height - m_fontSize);
}
void State_Game::initializeHUDText(sf::Text& text)
{
text.setFont(m_font);
text.setCharacterSize(m_fontSize);
text.setFillColor(APP_COLOR);
}
void State_Game::setWindowOutline()
{
m_background.setSize(m_gameView.getSize() - sf::Vector2f(2 * m_outlineThickness, 2 * m_outlineThickness));
m_background.setPosition(m_levelManager.getScreenCenter() - m_background.getSize() / 2.f);
m_background.setFillColor(sf::Color::Transparent);
m_background.setOutlineColor(APP_COLOR);
m_background.setOutlineThickness(m_outlineThickness);
}
void State_Game::setupHelpPanel()
{
m_helpPanel.setSize(m_helpPanelSize);
m_helpPanel.setOrigin(m_helpPanel.getSize() / 2.f);
m_helpPanel.setPosition(m_view.getCenter());
m_helpPanel.setFillColor(BGD_COLOR);
m_helpPanel.setOutlineColor(APP_COLOR);
m_helpPanel.setOutlineThickness(m_outlineThickness);
m_helpPanelTitle.setFont(m_font);
m_helpPanelTitle.setCharacterSize(m_fontSize + 20);
m_helpPanelTitle.setString("HELP");
m_helpPanelTitle.setOrigin(m_helpPanelTitle.getLocalBounds().width / 2.f, m_helpPanelTitle.getLocalBounds().height / 2.f);
m_helpPanelTitle.setFillColor(APP_COLOR);
m_helpPanelTitle.setPosition(m_helpPanel.getPosition().x, m_helpPanel.getPosition().y - m_helpPanel.getSize().y / 2.f);
m_helpPanelText.setFont(m_font);
m_helpPanelText.setCharacterSize(m_fontSize);
m_helpPanelText.setString("Move (Mouse)\nShoot (Mouse L)\nPause (P)\nHelp (H)\nMusic (M)\nSound (S)");
m_helpPanelText.setFillColor(APP_COLOR);
m_helpPanelText.setOrigin(m_helpPanelText.getLocalBounds().width / 2.f, m_helpPanelText.getLocalBounds().height / 2.f);
m_helpPanelText.setPosition(m_helpPanel.getPosition().x, m_helpPanel.getPosition().y);
}
sf::FloatRect State_Game::getGameViewSpace()
{
sf::Vector2f viewCenter = m_gameView.getCenter();
sf::Vector2f viewSize = m_gameView.getSize();
return sf::FloatRect(viewCenter - viewSize / 2.f, viewSize);
}
void State_Game::showNewScore(const unsigned int score)
{
m_showingNewScore = true;
m_showNewScoreTimer = 0.f;
m_newScoreText.setString("+" + std::to_string(score));
}