aboutsummaryrefslogtreecommitdiff
path: root/src/games/tetris/Tetris.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/games/tetris/Tetris.cpp')
-rw-r--r--src/games/tetris/Tetris.cpp259
1 files changed, 131 insertions, 128 deletions
diff --git a/src/games/tetris/Tetris.cpp b/src/games/tetris/Tetris.cpp
index d26649f..3370e78 100644
--- a/src/games/tetris/Tetris.cpp
+++ b/src/games/tetris/Tetris.cpp
@@ -1,3 +1,4 @@
+#include <games/Game.hpp>
#include <games/tetris/Tetromino.hpp>
#include <games/tetris/Tetris.hpp>
#include <renderer/Renderer.hpp>
@@ -8,76 +9,72 @@
#include <fstream>
-// Todo: change to new font scaling api in imgui first
-// Todo: test text with hardcoded gap + dummy to ensure it gets placed as expected
-Tetris::Tetris() :
- m_ActiveTetromino(m_Board),
- m_NextTetromino(m_Board)
+void
+Tetris::Start()
{
- m_TetrominoCounters[(size_t)m_ActiveTetromino.GetId()] += 1;
+ m_game_status = game_resuming;
+
+ m_tlast_milliseconds = SDL_GetTicks();
+ m_dt_remaining_seconds = 0.0f;
+
+ m_board.Reset();
+ m_active_tetromino.Reinit(m_board.m_bitmap);
+ m_next_tetromino.Reinit(m_board.m_bitmap);
+ m_tetromino_counters[(size_t)m_active_tetromino.GetId()] += 1;
+
+ memset(m_tetromino_counters, 0, sizeof(m_tetromino_counters));
+ m_score = 0;
+ m_line_counter = 0;
+ m_starting_level = 0;
+ m_level = 0;
+ m_softdrop_counter = 0;
}
-void Tetris::Restart() {
- m_RunningState = TetrisRunningState::Resume;
- m_DtInSecondsRemaining = 0.0f;
- m_MillisecondsSinceT0Last = SDL_GetTicks();
-
- // Todo: Don't reconstruct! Make reset methods.
- m_Board = Board();
- m_ActiveTetromino = Tetromino(m_Board);
- m_NextTetromino = Tetromino(m_Board);
-
- memset(m_TetrominoCounters, 0, sizeof(m_TetrominoCounters));
- m_Score = 0;
- m_LineCounter = 0;
- m_StartingLevel = 0;
- m_Level = 0;
- m_SoftdropCounter = 0;
-}
-
-bool Tetris::Update(std::vector<SDL_Event> &events) {
+bool
+Tetris::Update(std::vector<SDL_Event> &events)
+{
Color clear_color = {0.2f, 0.2f, 0.2f, 1.0f};
g_renderer.SetCameraSize(4.0f, 3.0f);
g_renderer.Clear(clear_color);
- if (m_RunningState == TetrisRunningState::Restart) {
- Restart();
+
+ if (m_game_status == game_starting) {
+ Start();
}
- uint64_t milliseconds_since_t0 = SDL_GetTicks();
- uint64_t milliseconds_since_t0_last = m_MillisecondsSinceT0Last;
- uint64_t milliseconds_dt = milliseconds_since_t0 - milliseconds_since_t0_last;
- float seconds_dt = static_cast<float>(milliseconds_dt) / 1000.0f;
- m_MillisecondsSinceT0Last = milliseconds_since_t0;
+ float dt = ProcessDt();
- if (m_RunningState == TetrisRunningState::Resume) {
- uint32_t harddrop_count = GetHarddropCount(seconds_dt);
- while (harddrop_count) {
- bool moved_down = m_ActiveTetromino.MaybeMoveDown();
+
+ if (m_game_status == game_resuming) {
+ uint32_t softdrop_count = GetSoftdropCount(dt); // side-effect: m_dt_remaining_seconds
+ for (uint32_t i{0}; i < softdrop_count; i++) {
+ bool moved_down = m_active_tetromino.MaybeMoveDown();
if (!moved_down) {
HandleTetrominoPlacement();
}
- harddrop_count--;
}
}
for (auto &event : events) {
- using enum TetrisRunningState;
- switch (m_RunningState) {
- case Resume: UpdateResumeState(event); break;
- case Pause: UpdatePauseState(event); break;
+ switch (m_game_status) {
+ case game_resuming: UpdateResumeState(event); break;
+ case game_paused: UpdatePauseState(event); break;
default:;
}
}
- Draw();
+
+ if (m_game_status == game_exit) {
+ return false;
+ }
- bool keep_running = m_RunningState != TetrisRunningState::Exit;
- return keep_running;
+ Draw();
+
+ return true;
}
void Tetris::UpdateResumeState(SDL_Event &event) {
@@ -85,23 +82,23 @@ void Tetris::UpdateResumeState(SDL_Event &event) {
case SDL_EVENT_KEY_DOWN: {
auto key = event.key.key;
if (key == SDLK_RIGHT) {
- m_ActiveTetromino.MaybeMoveHorizontally(Tetromino::right);
+ m_active_tetromino.MaybeMoveHorizontally(Tetromino::right);
} else if (key == SDLK_LEFT) {
- m_ActiveTetromino.MaybeMoveHorizontally(Tetromino::left);
+ m_active_tetromino.MaybeMoveHorizontally(Tetromino::left);
} else if (key == SDLK_DOWN) {
- bool moved_down = m_ActiveTetromino.MaybeMoveDown();
+ bool moved_down = m_active_tetromino.MaybeMoveDown();
if (!moved_down) {
HandleTetrominoPlacement();
}
else {
- m_SoftdropCounter++;
+ m_softdrop_counter++;
}
} else if (key == SDLK_X) {
- m_ActiveTetromino.MaybeRotate(Tetromino::rotate_clockwise);
+ m_active_tetromino.MaybeRotate(Tetromino::rotate_clockwise);
} else if (key == SDLK_Z || key == SDLK_Y) {
- m_ActiveTetromino.MaybeRotate(Tetromino::rotate_counter_clockwise);
+ m_active_tetromino.MaybeRotate(Tetromino::rotate_counter_clockwise);
} else if (key == SDLK_ESCAPE) {
- m_RunningState = TetrisRunningState::Pause;
+ m_game_status = game_paused;
}
}
default:;
@@ -113,75 +110,81 @@ void Tetris::UpdatePauseState(SDL_Event &event) {
case SDL_EVENT_KEY_DOWN: {
auto key = event.key.key;
if (key == SDLK_ESCAPE) {
- m_RunningState = TetrisRunningState::Resume;
+ m_game_status = game_resuming;
}
}
default:;
}
}
-void Tetris::HandleTetrominoPlacement() {
- int32_t rows_cleared = m_Board.PlaceTetromino(m_ActiveTetromino);
+void
+Tetris::HandleTetrominoPlacement()
+{
+ int32_t rows_cleared = m_board.PlaceTetromino(m_active_tetromino);
- m_ActiveTetromino = m_NextTetromino;
- m_NextTetromino = Tetromino{m_Board};
+ m_active_tetromino = m_next_tetromino;
+ m_next_tetromino.Reinit(m_board.m_bitmap);
- if (m_ActiveTetromino.IsCollisionWithBoard()) {
+ if (m_active_tetromino.IsCollisionWithBoard()) {
HandleGameOver();
return;
}
- m_LineCounter += rows_cleared;
- m_TetrominoCounters[m_ActiveTetromino.GetId()] += 1;
+ m_line_counter += rows_cleared;
+ m_tetromino_counters[m_active_tetromino.GetId()] += 1;
if (rows_cleared == 1) {
- m_Score += 40 * (m_Level + 1);
+ m_score += 40 * (m_level + 1);
}
else if (rows_cleared == 2) {
- m_Score += 100 * (m_Level + 1);
+ m_score += 100 * (m_level + 1);
}
else if (rows_cleared == 3) {
- m_Score += 300 * (m_Level + 1);
+ m_score += 300 * (m_level + 1);
}
else if (rows_cleared == 4) {
- m_Score += 1200 * (m_Level + 1);
+ m_score += 1200 * (m_level + 1);
}
- m_Score += m_SoftdropCounter;
- m_SoftdropCounter = 0;
+ m_score += m_softdrop_counter;
+ m_softdrop_counter = 0;
- m_Level = m_StartingLevel + m_LineCounter / 10;
+ m_level = m_starting_level + m_line_counter / 10;
}
-uint32_t Tetris::GetHarddropCount(float dt) {
+uint32_t
+Tetris::GetSoftdropCount(float dt)
+{
float nes_frame_time = 1.0f / 60;
int32_t nes_frames_per_cell;
- if (m_Level <= 8) nes_frames_per_cell = 48 - m_Level * 5;
- else if (m_Level == 9) nes_frames_per_cell = 6;
- else if (m_Level <= 12) nes_frames_per_cell = 5;
- else if (m_Level <= 15) nes_frames_per_cell = 4;
- else if (m_Level <= 18) nes_frames_per_cell = 3;
- else if (m_Level <= 28) nes_frames_per_cell = 2;
+ if (m_level <= 8) nes_frames_per_cell = 48 - m_level * 5;
+ else if (m_level == 9) nes_frames_per_cell = 6;
+ else if (m_level <= 12) nes_frames_per_cell = 5;
+ else if (m_level <= 15) nes_frames_per_cell = 4;
+ else if (m_level <= 18) nes_frames_per_cell = 3;
+ else if (m_level <= 28) nes_frames_per_cell = 2;
else nes_frames_per_cell = 1;
float dt_level = static_cast<float>(nes_frames_per_cell) * nes_frame_time;
- float dt_total = m_DtInSecondsRemaining + dt;
- uint32_t harddrop_count = 0;
- while (dt_total > dt_level) {
- harddrop_count += 1;
- dt_total -= dt_level;
+ uint32_t softdrop_count = 0;
+ while (dt > dt_level) {
+ softdrop_count += 1;
+ dt -= dt_level;
}
- m_DtInSecondsRemaining = dt_total;
- return harddrop_count;
+
+ m_dt_remaining_seconds = dt;
+ return softdrop_count;
}
-void Tetris::HandleGameOver() {
- m_RunningState = TetrisRunningState::GameOver;
+void
+Tetris::HandleGameOver()
+{
+ m_game_status = game_over;
const char *filepath = "tetris_highscore.txt";
int32_t highscore = 0;
@@ -195,16 +198,16 @@ void Tetris::HandleGameOver() {
SDL_LogInfo(0, "Tetris: cannot open tetris_highscore.txt for reading");
}
- if (highscore > 0 && highscore > m_HighScore) {
- m_HighScore = highscore;
+ if (highscore > 0 && highscore > m_highscore) {
+ m_highscore = highscore;
}
- if (m_Score > m_HighScore) {
- m_HighScore = m_Score;
+ if (m_score > m_highscore) {
+ m_highscore = m_score;
std::ofstream highscore_file_out { filepath };
if (highscore_file_out) {
- highscore_file_out << m_HighScore << std::endl;
+ highscore_file_out << m_highscore << std::endl;
highscore_file_out.close();
}
else {
@@ -213,9 +216,11 @@ void Tetris::HandleGameOver() {
}
}
-void Tetris::Draw() {
- m_Board.Draw(m_Level);
- m_ActiveTetromino.Draw();
+void
+Tetris::Draw()
+{
+ m_board.Draw(m_level);
+ m_active_tetromino.Draw();
DrawNextTetromino();
DrawStatistics();
@@ -224,52 +229,44 @@ void Tetris::Draw() {
DrawScore();
// Todo: Use transparency
- if (m_RunningState == TetrisRunningState::Pause) {
- DrawPauseMenu();
+ if (m_game_status == game_paused) {
+ DrawGamePausedMenu();
}
- else if (m_RunningState == TetrisRunningState::GameOver) {
+ else if (m_game_status == game_over) {
DrawGameOverMenu();
}
}
-void Tetris::DrawPauseMenu() {
- ImGui::Begin("TetrisPause", nullptr, s_MenuImGuiWindowFlags);
- if (ImGui::Button("Resume")) {
- m_RunningState = TetrisRunningState::Resume;
- }
- if (ImGui::Button("Restart")) {
- m_RunningState = TetrisRunningState::Restart;
- }
- if (ImGui::Button("Exit")) {
- m_RunningState = TetrisRunningState::Exit;
- }
- ImGui::End();
-}
-
-void Tetris::DrawGameOverMenu() {
+void
+Tetris::DrawGameOverMenu()
+{
ImGui::Begin("TetrisGameOver", nullptr, s_MenuImGuiWindowFlags);
- ImGui::Text("Score = %d", m_Score);
- ImGui::Text("HighScore = %d", m_HighScore);
+ ImGui::Text("Score = %d", m_score);
+ ImGui::Text("HighScore = %d", m_highscore);
if (ImGui::Button("Restart")) {
- m_RunningState = TetrisRunningState::Restart;
+ m_game_status = game_starting;
}
if (ImGui::Button("Exit")) {
- m_RunningState = TetrisRunningState::Exit;
+ m_game_status = game_exit;
}
ImGui::End();
}
-void Tetris::DrawLineCounter() {
+void
+Tetris::DrawLineCounter()
+{
V2F32 view_pos = {0.5f, 2.6f};
ImVec2 screen_pos = g_renderer.ViewPosToScreenPosImGui(view_pos);
ImGui::SetNextWindowPos(screen_pos);
ImGui::Begin("TetrisLines", nullptr, s_DefaultImGuiWindowFlags);
- ImGui::Text("LINES - %d", m_LineCounter);
+ ImGui::Text("LINES - %d", m_line_counter);
ImGui::End();
}
-void Tetris::DrawStatistics() {
+void
+Tetris::DrawStatistics()
+{
V2F32 view_tetrominoes_pos = {0.4f, 1.8f};
V2F32 view_advance = {0.0f, 0.2f};
@@ -313,36 +310,40 @@ void Tetris::DrawStatistics() {
ImGui::SetNextWindowPos(screen_text_pos);
ImGui::Begin("TetrisStatistics", nullptr, s_DefaultImGuiWindowFlags);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::t_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::t_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::j_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::j_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::z_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::z_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::o_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::o_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::s_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::s_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::l_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::l_piece]);
ImGui::Dummy(screen_text_gap);
- ImGui::Text("%d", m_TetrominoCounters[Tetromino::i_piece]);
+ ImGui::Text("%d", m_tetromino_counters[Tetromino::i_piece]);
ImGui::Dummy(screen_text_gap);
ImGui::End();
}
-void Tetris::DrawScore() {
+void
+Tetris::DrawScore()
+{
V2F32 view_pos = {3.0f, 2.2f};
ImVec2 screen_pos = g_renderer.ViewPosToScreenPosImGui(view_pos);
ImGui::SetNextWindowPos(screen_pos);
ImGui::Begin("TetrisScore", nullptr, s_DefaultImGuiWindowFlags);
ImGui::Text("Score");
- ImGui::Text("%d", m_Score);
+ ImGui::Text("%d", m_score);
ImGui::End();
}
-void Tetris::DrawNextTetromino() {
+void
+Tetris::DrawNextTetromino()
+{
V2F32 text_view_pos = {3.0f, 1.8f};
ImVec2 text_screen_pos = g_renderer.ViewPosToScreenPosImGui(text_view_pos);
@@ -353,17 +354,19 @@ void Tetris::DrawNextTetromino() {
V2F32 tetromino_view_pos = {3.0, 1.4f};
- Tetromino::Draw(m_NextTetromino.GetId(), 0, tetromino_view_pos, 0.5f);
+ Tetromino::Draw(m_next_tetromino.GetId(), 0, tetromino_view_pos, 0.5f);
}
-void Tetris::DrawLevel() {
+void
+Tetris::DrawLevel()
+{
V2F32 view_pos = {3.0f, 1.2f};
ImVec2 screen_pos = g_renderer.ViewPosToScreenPosImGui(view_pos);
ImGui::SetNextWindowPos(screen_pos);
ImGui::Begin("TetrisLevel", nullptr, s_DefaultImGuiWindowFlags);
ImGui::Text("Level");
- ImGui::Text("%d", m_Level);
+ ImGui::Text("%d", m_level);
ImGui::End();
}