From 606d028dac5118329e7561af33b15988db84465f Mon Sep 17 00:00:00 2001 From: fschildt Date: Mon, 6 Oct 2025 09:25:04 +0200 Subject: make everything prettier --- src/games/Game.cpp | 59 ++++++-- src/games/Game.hpp | 27 +++- src/games/breakout/Breakout.cpp | 66 --------- src/games/breakout/Breakout.hpp | 38 ----- src/games/minesweeper/Minesweeper.cpp | 58 ++------ src/games/minesweeper/Minesweeper.hpp | 28 +--- src/games/snake/Snake.cpp | 269 ++++++++++++++++++---------------- src/games/snake/Snake.hpp | 50 +++---- src/games/tetris/Board.cpp | 52 ++++--- src/games/tetris/Board.hpp | 9 +- src/games/tetris/Tetris.cpp | 259 ++++++++++++++++---------------- src/games/tetris/Tetris.hpp | 45 ++---- src/games/tetris/Tetromino.cpp | 100 ++++++++----- src/games/tetris/Tetromino.hpp | 20 ++- src/main.cpp | 7 +- 15 files changed, 502 insertions(+), 585 deletions(-) delete mode 100644 src/games/breakout/Breakout.cpp delete mode 100644 src/games/breakout/Breakout.hpp (limited to 'src') diff --git a/src/games/Game.cpp b/src/games/Game.cpp index 7ed94eb..0520a36 100644 --- a/src/games/Game.cpp +++ b/src/games/Game.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include #include @@ -16,20 +15,16 @@ Game::Select(GameType type) return nullptr; } break; - case tetris: { - return std::make_unique(); + case minesweeper: { + return std::make_unique(); } break; case snake: { return std::make_unique(); } break; - case minesweeper: { - return std::make_unique(); - } break; - - case breakout: { - return std::make_unique(); + case tetris: { + return std::make_unique(); } break; InvalidDefaultCase; @@ -38,3 +33,49 @@ Game::Select(GameType type) return nullptr; } +float +Game::ProcessDt() +{ + uint64_t tnow_milliseconds = SDL_GetTicks(); + uint64_t tlast_milliseconds = m_tlast_milliseconds; + uint64_t dt_milliseconds = tnow_milliseconds - tlast_milliseconds; + + float dt_seconds = float(dt_milliseconds) / 1000.0f; + dt_seconds += m_dt_remaining_seconds; + + m_tlast_milliseconds = tnow_milliseconds; + m_dt_remaining_seconds = 0.0f; + + return dt_seconds; +} + +void +Game::DrawGameOverMenu() +{ + ImGui::Begin("DefaultGameOverMenu"); + ImGui::Text("Game Over."); + if (ImGui::Button("Play Again")) { + m_game_status = game_starting; + } + if (ImGui::Button("Exit")) { + m_game_status = game_exit; + } + ImGui::End(); +} + +void +Game::DrawGamePausedMenu() +{ + ImGui::Begin("DefaultGamePauseMenu"); + if (ImGui::Button("Resume")) { + m_game_status = game_resuming; + } + if (ImGui::Button("Restart")) { + m_game_status = game_starting; + } + if (ImGui::Button("Exit")) { + m_game_status = game_exit; + } + ImGui::End(); +} + diff --git a/src/games/Game.hpp b/src/games/Game.hpp index 1307e79..94d50cb 100644 --- a/src/games/Game.hpp +++ b/src/games/Game.hpp @@ -8,17 +8,21 @@ #include -struct SDL_Window; - - class Game { public: enum GameType { no_game, - tetris, - snake, minesweeper, - breakout + snake, + tetris + }; + + enum GameStatus { + game_starting, + game_resuming, + game_over, + game_paused, + game_exit }; static std::unique_ptr Select(GameType type); @@ -27,5 +31,16 @@ public: Game() = default; virtual ~Game() = default; virtual bool Update(std::vector& events) = 0; + + +protected: + void DrawGameOverMenu(); + void DrawGamePausedMenu(); + + float ProcessDt(); + + GameStatus m_game_status {game_starting}; + float m_dt_remaining_seconds {0.0f}; + uint64_t m_tlast_milliseconds {SDL_GetTicks()}; }; diff --git a/src/games/breakout/Breakout.cpp b/src/games/breakout/Breakout.cpp deleted file mode 100644 index 65fafd6..0000000 --- a/src/games/breakout/Breakout.cpp +++ /dev/null @@ -1,66 +0,0 @@ -#include - -#include - - -bool -Breakout::Update(std::vector& events) -{ - for (auto& event : events) { - if (m_status == pause) { - ProcessEventDuringPause(event); - } - else { - ProcessEventDuringResume(event); - } - } - - if (m_status == pause) { - DrawPauseMenu(); - } - if (m_status == exit) { - return false; - } - - return true; -} - -void -Breakout::ProcessEventDuringResume(SDL_Event& event) -{ - switch (event.type) { - case SDL_EVENT_KEY_DOWN: { - if (event.key.key == SDLK_ESCAPE) { - m_status = pause; - } - } break; - default:; - } -} - -void -Breakout::ProcessEventDuringPause(SDL_Event &event) -{ - switch (event.type) { - case SDL_EVENT_KEY_DOWN: { - if (event.key.key == SDLK_ESCAPE) { - m_status = resume; - } - } break; - default:; - } -} - -void -Breakout::DrawPauseMenu() -{ - ImGui::Begin("BreakoutPause"); - if (ImGui::Button("Resume")) { - m_status = resume; - } - if (ImGui::Button("Exit")) { - m_status = exit; - } - ImGui::End(); -} - diff --git a/src/games/breakout/Breakout.hpp b/src/games/breakout/Breakout.hpp deleted file mode 100644 index 9f2a0ef..0000000 --- a/src/games/breakout/Breakout.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include - - -struct Ball { - V3F32 pos; - float radius; -}; - - -class Breakout : public Game { - enum GameStatus { - resume, - pause, - exit - }; - -public: - Breakout() = default; - bool Update(std::vector &events) override; - -private: - void ProcessEventDuringPause(SDL_Event& event); - void ProcessEventDuringResume(SDL_Event& event); - - void Draw(); - void DrawPauseMenu(); - - -private: - GameStatus m_status; - - Circle m_circle; -}; - diff --git a/src/games/minesweeper/Minesweeper.cpp b/src/games/minesweeper/Minesweeper.cpp index a1886ff..e110acb 100644 --- a/src/games/minesweeper/Minesweeper.cpp +++ b/src/games/minesweeper/Minesweeper.cpp @@ -1,3 +1,4 @@ +#include "games/Game.hpp" #include #include @@ -117,31 +118,31 @@ Minesweeper::Update(std::vector& events) g_renderer.Clear({0.3f, 0.2f, 0.3f}); for (SDL_Event &event : events) { - if (m_run_state == exit) { + if (m_game_status == game_exit) { return false; } - else if (m_run_state == pause) { + else if (m_game_status == game_paused) { ProcessEventDuringPause(event); } - else if (m_run_state == resume) { + else if (m_game_status== game_resuming) { ProcessEventDuringResume(event); } } - if (m_run_state == exit) { + if (m_game_status == game_exit) { return false; } - if (m_run_state == pause) { + if (m_game_status == game_paused) { DrawBoard(); - DrawPauseMenu(); + DrawGamePausedMenu(); } - else if (m_run_state == start) { + else if (m_game_status == game_starting) { DrawStartMenu(); } - else if (m_run_state == resume) { + else if (m_game_status == game_resuming) { DrawBoard(); } - else if (m_run_state == game_over) { + else if (m_game_status == game_over) { DrawBoard(); DrawGameOverMenu(); } @@ -155,7 +156,7 @@ Minesweeper::ProcessEventDuringPause(SDL_Event &event) switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.key == SDLK_ESCAPE) { - m_run_state = resume; + m_game_status = game_resuming; } } break; @@ -169,7 +170,7 @@ Minesweeper::ProcessEventDuringResume(SDL_Event &event) switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.key == SDLK_ESCAPE) { - m_run_state = pause; + m_game_status = game_paused; } } break; @@ -200,7 +201,7 @@ Minesweeper::ProcessEventDuringResume(SDL_Event &event) if (IsMine(x, y)) { m_is_covered_bitmap[y] &= ~(1 << x); UncoverMines(); - m_run_state = game_over; + m_game_status = game_over; } else { Uncover(x, y); @@ -301,22 +302,6 @@ Minesweeper::ScreenPosToViewPos(V2F32 screen_pos) return view_pos; } -void -Minesweeper::DrawPauseMenu() -{ - ImGui::Begin("MinesweeperPause"); - if (ImGui::Button("Resume")) { - m_run_state = resume; - } - if (ImGui::Button("Restart")) { - m_run_state = start; - } - if (ImGui::Button("Exit")) { - m_run_state = exit; - } - ImGui::End(); -} - void Minesweeper::DrawStartMenu() { @@ -332,23 +317,10 @@ Minesweeper::DrawStartMenu() } if (ImGui::Button("Start")) { Reset(m_difficulty); - m_run_state = resume; - } - if (ImGui::Button("Exit")) { - m_run_state = exit; - } - ImGui::End(); -} - -void -Minesweeper::DrawGameOverMenu() -{ - ImGui::Begin("MinesweeperGameOverMenu"); - if (ImGui::Button("Play Again")) { - m_run_state = start; + m_game_status = game_resuming; } if (ImGui::Button("Exit")) { - m_run_state = exit; + m_game_status = game_exit; } ImGui::End(); } diff --git a/src/games/minesweeper/Minesweeper.hpp b/src/games/minesweeper/Minesweeper.hpp index f29df14..867ca6a 100644 --- a/src/games/minesweeper/Minesweeper.hpp +++ b/src/games/minesweeper/Minesweeper.hpp @@ -7,29 +7,8 @@ #include -namespace std { - template <> - struct hash { - size_t operator()(const V2ST& v) const { - size_t h1 = hash{}(v.x); - size_t h2 = hash{}(v.y); - return h1 ^ (h2 << 1); - } - }; -} - - - class Minesweeper : public Game { public: - enum RunState { - start, - pause, - resume, - game_over, - exit - }; - enum Difficulty { beginner, intermediate, @@ -66,8 +45,6 @@ private: private: void DrawBoard(); void DrawStartMenu(); - void DrawPauseMenu(); - void DrawGameOverMenu(); private: @@ -77,16 +54,13 @@ private: private: - RunState m_run_state = start; Difficulty m_difficulty = beginner; float m_world_width = 4.0f; float m_world_height = 3.0f; int32_t m_grid_width; - int32_t m_grid_height; - - V2F32 m_grid_pos; + int32_t m_grid_height; V2F32 m_grid_pos; V2F32 m_cell_outer_size; V2F32 m_cell_inner_size; diff --git a/src/games/snake/Snake.cpp b/src/games/snake/Snake.cpp index 4c6ca18..7969616 100644 --- a/src/games/snake/Snake.cpp +++ b/src/games/snake/Snake.cpp @@ -1,196 +1,218 @@ -#include "renderer/Renderer.hpp" +#include "common/defs.hpp" +#include #include +#include #include +std::mt19937 Snake::s_rng{std::random_device{}()}; + + Snake::Snake() { - m_IsPaused = false; - m_IsRunning = true; - - m_DtInSecondsRemaining = 0.0f; - m_LastMillisecondsSinceT0 = SDL_GetTicks(); + static_assert(max_map_width <= sizeof(m_body_bitmap[0])*8); + static_assert(max_map_height <= sizeof(m_body_bitmap[0])*8); +} - m_TilesPerSecond = 4.0f; - m_Direction = right; - m_LastAdvancedDirection = right; +void +Snake::Start(int32_t map_width, int32_t map_height) +{ + m_dt_remaining_seconds = 0.0f; + m_tlast_milliseconds = SDL_GetTicks(); - m_MapWidth = 16; - m_MapHeight = 16; - assert(MAX_MAP_WIDTH <= 64); // m_BodyBitmap is uint64_t[]. We can't exceed that! - assert(MAX_MAP_HEIGHT <= 64); - assert(m_MapWidth <= MAX_MAP_WIDTH); - assert(m_MapHeight <= MAX_MAP_WIDTH); + m_direction = right; + m_last_advanced_direction = right; - m_Tail = 0; - m_Head = 1; - memset(m_BodyBitmap, 0, sizeof(m_BodyBitmap)); + assert(map_width <= max_map_width); + assert(map_height <= max_map_height); + m_map_width = map_width; + m_map_height = map_height; - int32_t head_x = m_MapWidth / 2; - int32_t head_y = m_MapHeight / 2; - m_BodyPositions[0] = {head_x -1, head_y}; - m_BodyPositions[1] = {head_x, head_y}; + m_tail = 0; + m_head = 1; - m_Rng = std::mt19937((std::random_device()())); - m_Dist = std::uniform_int_distribution(0, m_MapWidth * m_MapHeight - 3); + int32_t head_x = m_map_width / 2; + int32_t head_y = m_map_height / 2; + m_body_positions[0] = {head_x -1, head_y}; + m_body_positions[1] = {head_x, head_y}; + memset(m_body_bitmap, 0, sizeof(m_body_bitmap)); + m_dist = std::uniform_int_distribution(0, m_map_width*m_map_height - 3); SpawnFood(); -} - -bool Snake::Update(std::vector &events) { - uint64_t milliseconds_since_t0 = SDL_GetTicks(); - uint64_t milliseconds_since_t0_last = m_LastMillisecondsSinceT0; - uint64_t dt_in_milliseconds = milliseconds_since_t0 - milliseconds_since_t0_last; - float dt_in_seconds = (float)dt_in_milliseconds / 1000.0f; - m_LastMillisecondsSinceT0 = milliseconds_since_t0; + m_game_status = game_resuming; +} +bool +Snake::Update(std::vector &events) +{ Color clear_color = {0.3f, 0.3f, 0.3f, 1.0f}; g_renderer.SetCameraSize(4.0f, 3.0f); g_renderer.Clear(clear_color); + if (m_game_status == game_starting) { + int32_t map_width = 16; + int32_t map_height = 16; + Start(map_width, map_height); + } + + for (SDL_Event &event : events) { - if (!m_IsRunning) { - printf("event loop is running just false\n"); - return false; + if (m_game_status == game_resuming) { + ProcessEventDuringResume(event); } - if (m_IsPaused) { + else if (m_game_status == game_paused) { ProcessEventDuringPause(event); } - else { - ProcessEventDuringResume(event); - } } - if (!m_IsPaused) { - MaybeMoveSnake(dt_in_seconds); + + float dt = ProcessDt(); + + switch (m_game_status) { + case game_starting: { + } break; + case game_resuming: { + MaybeMoveSnake(dt); + } break; + case game_over: { + DrawGameOverMenu(); + } break; + case game_paused: { + DrawGamePausedMenu(); + } break; + case game_exit: { + return false; + } break; } Draw(); - DoImgui(); - - return m_IsRunning; + return true; } -void Snake::MaybeMoveSnake(float dt_in_seconds) { - float dt_in_seconds_to_use = m_DtInSecondsRemaining + dt_in_seconds; - float tiles_per_second = m_TilesPerSecond; +void +Snake::MaybeMoveSnake(float dt) +{ float seconds_per_tile = 1.0f / tiles_per_second; - while (dt_in_seconds_to_use > seconds_per_tile) { - V2I32 head_pos = m_BodyPositions[m_Head]; - V2I32 tail_pos = m_BodyPositions[m_Tail]; + while (dt > seconds_per_tile) { + V2I32 head_pos = m_body_positions[m_head]; + V2I32 tail_pos = m_body_positions[m_tail]; // find head_pos - if (m_Direction == up) { + if (m_direction == up) { head_pos.y += 1; } - else if (m_Direction == down) { + else if (m_direction == down) { head_pos.y -= 1; } - else if (m_Direction == right) { + else if (m_direction == right) { head_pos.x += 1; } - else if (m_Direction == left) { + else if (m_direction == left) { head_pos.x -= 1; } - if ((head_pos.x < 0 || head_pos.x >= m_MapWidth) || - (head_pos.y < 0 || head_pos.y >= m_MapHeight)) + if ((head_pos.x < 0 || head_pos.x >= m_map_width) || + (head_pos.y < 0 || head_pos.y >= m_map_height)) { - m_IsRunning = false; + m_game_status = game_over; return; } uint64_t head_bit = 1 << head_pos.x; - uint64_t body_bits = m_BodyBitmap[head_pos.y]; + uint64_t body_bits = m_body_bitmap[head_pos.y]; if (head_pos.y == tail_pos.y) { body_bits &= ~(1 << tail_pos.x); } if (head_bit & body_bits) { - m_IsRunning = false; + m_game_status = game_over; return; } // advance head - int32_t max_positions = sizeof(m_BodyPositions) / sizeof(m_BodyPositions[0]); - m_Head += 1; - if (m_Head >= max_positions) { - m_Head = 0; + int32_t max_positions = ARRAY_COUNT(m_body_positions); + m_head += 1; + if (m_head >= max_positions) { + m_head = 0; } - m_BodyPositions[m_Head] = head_pos; - m_BodyBitmap[head_pos.y] |= (1 << head_pos.x); + m_body_positions[m_head] = head_pos; + m_body_bitmap[head_pos.y] |= (1 << head_pos.x); - if (m_BodyPositions[m_Head] == m_FoodPosition) { + if (m_body_positions[m_head] == m_food_position) { SpawnFood(); } else { // advance tail - V2I32 next_tail_pos = m_BodyPositions[m_Tail]; - m_BodyBitmap[next_tail_pos.y] &= ~(1 << next_tail_pos.x); + V2I32 next_tail_pos = m_body_positions[m_tail]; + m_body_bitmap[next_tail_pos.y] &= ~(1 << next_tail_pos.x); - m_Tail += 1; - if (m_Tail >= max_positions) { - m_Tail = 0; + m_tail += 1; + if (m_tail >= max_positions) { + m_tail = 0; } } - m_LastAdvancedDirection = m_Direction; - dt_in_seconds_to_use -= seconds_per_tile; + m_last_advanced_direction = m_direction; + dt -= seconds_per_tile; } - m_DtInSecondsRemaining = dt_in_seconds_to_use; + m_dt_remaining_seconds = dt; } -void Snake::ProcessEventDuringPause(SDL_Event &event) { +void +Snake::ProcessEventDuringPause(SDL_Event &event) +{ switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.key == SDLK_ESCAPE) { - m_IsPaused = false; + m_game_status = game_resuming; } } default:; } } -void Snake::ProcessEventDuringResume(SDL_Event &event) { +void +Snake::ProcessEventDuringResume(SDL_Event &event) +{ switch (event.type) { case SDL_EVENT_KEY_DOWN: { if (event.key.key == SDLK_UP) { - if (m_LastAdvancedDirection == right || - m_LastAdvancedDirection == left) + if (m_last_advanced_direction == right || + m_last_advanced_direction == left) { - m_Direction = up; + m_direction = up; } } else if (event.key.key == SDLK_DOWN) { - if (m_LastAdvancedDirection == right || - m_LastAdvancedDirection == left) + if (m_last_advanced_direction == right || + m_last_advanced_direction == left) { - m_Direction = down; + m_direction = down; } } else if (event.key.key == SDLK_RIGHT) { - if (m_LastAdvancedDirection == up || - m_LastAdvancedDirection == down) + if (m_last_advanced_direction == up || + m_last_advanced_direction == down) { - m_Direction = right; + m_direction = right; } } else if (event.key.key == SDLK_LEFT) { - if (m_LastAdvancedDirection == up || - m_LastAdvancedDirection == down) + if (m_last_advanced_direction == up || + m_last_advanced_direction == down) { - m_Direction = left; + m_direction = left; } } else if (event.key.key == SDLK_ESCAPE) { - m_IsPaused = true; + m_game_status = game_paused; } } @@ -198,21 +220,23 @@ void Snake::ProcessEventDuringResume(SDL_Event &event) { } } -void Snake::SpawnFood() { - int32_t bit0_counts[MAX_MAP_HEIGHT]; +void +Snake::SpawnFood() +{ + int32_t bit0_counts[max_map_height]; int32_t bit0_count_total = 0; // count bits - for (int32_t y = 0; y < m_MapHeight; y++) { + for (int32_t y = 0; y < m_map_height; y++) { int32_t bit1_count = 0; - uint64_t bitmap_row = m_BodyBitmap[y]; + uint64_t bitmap_row = m_body_bitmap[y]; while (bitmap_row != 0) { bitmap_row = bitmap_row & (bitmap_row - 1); bit1_count += 1; } - int32_t bit0_count = m_MapWidth - bit1_count; + int32_t bit0_count = m_map_width - bit1_count; bit0_counts[y] = bit0_count; bit0_count_total += bit0_count; } @@ -221,13 +245,13 @@ void Snake::SpawnFood() { return; } - m_Dist.param(std::uniform_int_distribution::param_type(0, bit0_count_total - 1)); - int32_t bit0_index = m_Dist(m_Rng); + m_dist.param(std::uniform_int_distribution::param_type(0, bit0_count_total - 1)); + int32_t bit0_index = m_dist(s_rng); int32_t bit0_x = 0; int32_t bit0_y = 0; // find y - for (int32_t y = 0; y < m_MapHeight; y++) { + for (int32_t y = 0; y < m_map_height; y++) { if (bit0_index < bit0_counts[y]) { bit0_y = y; break; @@ -236,8 +260,8 @@ void Snake::SpawnFood() { } // find x - uint64_t bitmap_row_not = ~m_BodyBitmap[bit0_y]; - for (int32_t x = 0; x < m_MapWidth; x++) { + uint64_t bitmap_row_not = ~m_body_bitmap[bit0_y]; + for (int32_t x = 0; x < m_map_width; x++) { if (bitmap_row_not & 1) { if (bit0_index == 0) { bit0_x = x; @@ -248,23 +272,25 @@ void Snake::SpawnFood() { bitmap_row_not >>= 1; } - m_FoodPosition = {bit0_x, bit0_y}; + m_food_position = {bit0_x, bit0_y}; } -void Snake::Draw() { +void +Snake::Draw() +{ float world_width = 4.0f; float world_height = 3.0f; - float tile_size = (world_width / 2) / MAX_MAP_WIDTH; + float tile_size = (world_width / 2) / max_map_width; float bodypart_size = 0.8f * tile_size; float bodypart_offset = (tile_size - bodypart_size) / 2; - float map_view_width = tile_size * (float)m_MapWidth; - float map_view_height = tile_size * (float)m_MapHeight; + float map_view_width = tile_size * (float)m_map_width; + float map_view_height = tile_size * (float)m_map_height; float map_x = (world_width - map_view_width) / 2; float map_y = (world_height - map_view_height) / 2; - int32_t max_positions = sizeof(m_BodyPositions) / sizeof(m_BodyPositions[0]); + int32_t max_positions = ARRAY_COUNT(m_body_positions); /* draw map background */ @@ -282,12 +308,12 @@ void Snake::Draw() { /* draw snake */ // 1) if tail > head: advance to end first - int32_t tail = m_Tail; - if (tail > m_Head) { + int32_t tail = m_tail; + if (tail > m_head) { while (tail < max_positions) { V3F32 local_pos = { - (float)m_BodyPositions[tail].x * tile_size + bodypart_offset, - (float)m_BodyPositions[tail].y * tile_size + bodypart_offset, + (float)m_body_positions[tail].x * tile_size + bodypart_offset, + (float)m_body_positions[tail].y * tile_size + bodypart_offset, 1.0f }; V2F32 local_dim = {bodypart_size, bodypart_size}; @@ -312,10 +338,10 @@ void Snake::Draw() { tail = 0; } // 2) advance to head - while (tail <= m_Head) { + while (tail <= m_head) { V3F32 local_pos = { - (float)m_BodyPositions[tail].x * tile_size + bodypart_offset, - (float)m_BodyPositions[tail].y * tile_size + bodypart_offset, + (float)m_body_positions[tail].x * tile_size + bodypart_offset, + (float)m_body_positions[tail].y * tile_size + bodypart_offset, 1.0f }; V2F32 local_dim = {bodypart_size, bodypart_size}; @@ -341,8 +367,8 @@ void Snake::Draw() { /* draw food */ V3F32 pos = { - map_world_pos.x + (float)m_FoodPosition.x * tile_size + bodypart_offset, - map_world_pos.y + (float)m_FoodPosition.y * tile_size + bodypart_offset, + map_world_pos.x + (float)m_food_position.x * tile_size + bodypart_offset, + map_world_pos.y + (float)m_food_position.y * tile_size + bodypart_offset, 1.0f }; V2F32 dim = {bodypart_size, bodypart_size}; @@ -356,16 +382,3 @@ void Snake::Draw() { g_renderer.PushRectangle(rect, pos.z, color); } -void Snake::DoImgui() { - if (m_IsPaused) { - ImGui::Begin("SnakePause"); - if (ImGui::Button("Resume")) { - m_IsPaused = false; - } - if (ImGui::Button("Exit")) { - m_IsRunning = false; - } - ImGui::End(); - } -} - diff --git a/src/games/snake/Snake.hpp b/src/games/snake/Snake.hpp index 51d98fb..103255c 100644 --- a/src/games/snake/Snake.hpp +++ b/src/games/snake/Snake.hpp @@ -18,45 +18,39 @@ public: public: Snake(); - bool Update(std::vector &events) override; + bool Update(std::vector& events) override; private: - void ProcessEventDuringPause(SDL_Event &event); - void ProcessEventDuringResume(SDL_Event &event); + void ProcessEventDuringPause(SDL_Event& event); + void ProcessEventDuringResume(SDL_Event& event); + + void Start(int32_t map_width, int32_t map_height); void MaybeMoveSnake(float dt_in_seconds); void SpawnFood(); void Draw(); - void DoImgui(); - private: - static constexpr int32_t MAX_MAP_WIDTH = 16; - static constexpr int32_t MAX_MAP_HEIGHT = 16; - - bool m_IsPaused; - bool m_IsRunning; - - float m_DtInSecondsRemaining; - uint64_t m_LastMillisecondsSinceT0; - - float m_TilesPerSecond; - Direction m_Direction; - Direction m_LastAdvancedDirection; - - int32_t m_MapWidth; - int32_t m_MapHeight; - int32_t m_Tail; - int32_t m_Head; - uint64_t m_BodyBitmap[MAX_MAP_HEIGHT]; - V2I32 m_BodyPositions[MAX_MAP_WIDTH * MAX_MAP_HEIGHT]; - V2I32 m_FoodPosition; - - std::mt19937 m_Rng; - std::uniform_int_distribution m_Dist; + static constexpr int32_t max_map_width = 16; + static constexpr int32_t max_map_height = 16; + static constexpr float tiles_per_second = 4.0f; + + static std::mt19937 s_rng; + std::uniform_int_distribution m_dist; + + Direction m_direction; + Direction m_last_advanced_direction; + + int32_t m_map_width; + int32_t m_map_height; + int32_t m_tail {0}; + int32_t m_head {1}; + uint64_t m_body_bitmap[max_map_height]; + V2I32 m_body_positions[max_map_width * max_map_height]; + V2I32 m_food_position; }; diff --git a/src/games/tetris/Board.cpp b/src/games/tetris/Board.cpp index 1e57b2f..c1af5e1 100644 --- a/src/games/tetris/Board.cpp +++ b/src/games/tetris/Board.cpp @@ -1,23 +1,27 @@ -#include #include +#include #include -Board::Board() { +void +Board::Reset() +{ for (int y = 0; y < 2; y++) { - m_Bitmap[y] = 0xffff; // 1111111111111111 + m_bitmap[y] = 0xffff; // 1111111111111111 } for (int y = 2; y < 24; y++) { - m_Bitmap[y] = 0xe007; // 1110000000000111 + m_bitmap[y] = 0xe007; // 1110000000000111 } for (int y = 0; y < 22; y++) { for (int x = 0; x < 10; x++) { - m_Idmap[y][x] = Tetromino::tetromino_id_none; + m_idmap[y][x] = Tetromino::id_none; } } } -int32_t Board::PlaceTetromino(Tetromino &tetromino) { +int32_t +Board::PlaceTetromino(Tetromino &tetromino) +{ BoardPos pos = tetromino.GetPos(); Tetromino::TetrominoId id = tetromino.GetId(); uint16_t tetromino_bitmap[4]; @@ -25,10 +29,10 @@ int32_t Board::PlaceTetromino(Tetromino &tetromino) { // place in Board's Bitmap - m_Bitmap[pos.y+0] |= tetromino_bitmap[0]; - m_Bitmap[pos.y+1] |= tetromino_bitmap[1]; - m_Bitmap[pos.y+2] |= tetromino_bitmap[2]; - m_Bitmap[pos.y+3] |= tetromino_bitmap[3]; + m_bitmap[pos.y+0] |= tetromino_bitmap[0]; + m_bitmap[pos.y+1] |= tetromino_bitmap[1]; + m_bitmap[pos.y+2] |= tetromino_bitmap[2]; + m_bitmap[pos.y+3] |= tetromino_bitmap[3]; // place in Board's Idmap @@ -38,7 +42,7 @@ int32_t Board::PlaceTetromino(Tetromino &tetromino) { if (tetromino_bitmap[y] & bitmap_x) { int32_t idmap_x = pos.x + x - 3; int32_t idmap_y = pos.y + y - 2; - m_Idmap[idmap_y][idmap_x] = id; + m_idmap[idmap_y][idmap_x] = id; } } } @@ -47,7 +51,9 @@ int32_t Board::PlaceTetromino(Tetromino &tetromino) { return rows_cleared; } -int32_t Board::ClearRows(int32_t y0) { +int32_t +Board::ClearRows(int32_t y0) +{ int32_t rows_cleared = 0; int32_t y1 = y0 + 3; @@ -57,28 +63,30 @@ int32_t Board::ClearRows(int32_t y0) { } for (int32_t y = y0; y <= y1; y++) { - if (m_Bitmap[y] == 0xffff) { + if (m_bitmap[y] == 0xffff) { rows_cleared++; } else { - m_Bitmap[y-rows_cleared] = m_Bitmap[y]; - std::copy(m_Idmap[y-2], m_Idmap[y-2] + 10, m_Idmap[y-2-rows_cleared]); + m_bitmap[y-rows_cleared] = m_bitmap[y]; + std::copy(m_idmap[y-2], m_idmap[y-2] + 10, m_idmap[y-2-rows_cleared]); } } for (int32_t y = y1+1; y < 24; y++) { - m_Bitmap[y-rows_cleared] = m_Bitmap[y]; - std::copy(m_Idmap[y-2], m_Idmap[y-2] + 10, m_Idmap[y-2-rows_cleared]); + m_bitmap[y-rows_cleared] = m_bitmap[y]; + std::copy(m_idmap[y-2], m_idmap[y-2] + 10, m_idmap[y-2-rows_cleared]); } for (int32_t y = 24-rows_cleared; y < 24; y++) { - m_Bitmap[y] = 0xe007; - std::fill(m_Idmap[y-2], m_Idmap[y-2] + 10, Tetromino::tetromino_id_none); + m_bitmap[y] = 0xe007; + std::fill(m_idmap[y-2], m_idmap[y-2] + 10, Tetromino::id_none); } return rows_cleared; } -void Board::Draw(int32_t level) { +void +Board::Draw(int32_t level) +{ float world_width = 4.0f; float world_height = 3.0f; float tetromino_size_with_border = world_height / 20.0f; @@ -113,8 +121,8 @@ void Board::Draw(int32_t level) { // tetromino parts for (size_t y = 0; y < 20; y++) { for (size_t x = 0; x < 10; x++) { - Tetromino::TetrominoId tetromino_id = (Tetromino::TetrominoId)m_Idmap[y][x]; - if (tetromino_id < Tetromino::tetromino_id_count) { + Tetromino::TetrominoId tetromino_id = (Tetromino::TetrominoId)m_idmap[y][x]; + if (tetromino_id < Tetromino::id_count) { V2F32 local_pos = { (float)x * tetromino_size_with_border + tetromino_offset, (float)y * tetromino_size_with_border + tetromino_offset diff --git a/src/games/tetris/Board.hpp b/src/games/tetris/Board.hpp index 2e2edb2..a91556b 100644 --- a/src/games/tetris/Board.hpp +++ b/src/games/tetris/Board.hpp @@ -13,8 +13,7 @@ struct BoardPos { class Board { public: - Board(); - + void Reset(); int32_t PlaceTetromino(Tetromino &tetromino); void Draw(int32_t level); @@ -24,8 +23,8 @@ private: private: - friend class Tetromino; - uint16_t m_Bitmap[24]; - uint8_t m_Idmap[22][10]; + friend class Tetris; + uint16_t m_bitmap[24]; + uint8_t m_idmap[22][10]; }; 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 #include #include #include @@ -8,76 +9,72 @@ #include -// 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 &events) { +bool +Tetris::Update(std::vector &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(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(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(); } diff --git a/src/games/tetris/Tetris.hpp b/src/games/tetris/Tetris.hpp index e517f1c..b3ace1d 100644 --- a/src/games/tetris/Tetris.hpp +++ b/src/games/tetris/Tetris.hpp @@ -6,27 +6,18 @@ #include -enum class TetrisRunningState { - Resume, - Pause, - GameOver, - Restart, - Exit -}; - - class Tetris : public Game { public: - Tetris(); + Tetris() = default; bool Update(std::vector &events) override; void HandleTetrominoPlacement(); private: - void Restart(); + void Start(); void UpdateResumeState(SDL_Event &event); void UpdatePauseState(SDL_Event &event); - uint32_t GetHarddropCount(float dt); + uint32_t GetSoftdropCount(float dt); void HandleGameOver(); void Draw(); @@ -36,7 +27,6 @@ private: void DrawNextTetromino(); void DrawLevel(); - void DrawPauseMenu(); void DrawGameOverMenu(); private: @@ -45,23 +35,18 @@ private: private: - TetrisRunningState m_RunningState = TetrisRunningState::Resume; - - float m_DtInSecondsRemaining = 0.0f; - uint64_t m_MillisecondsSinceT0Last = SDL_GetTicks(); - - Board m_Board; - Tetromino m_ActiveTetromino; - Tetromino m_NextTetromino; - - int32_t m_TetrominoCounters[Tetromino::tetromino_id_count] {}; - int32_t m_Score = 0; - int32_t m_LineCounter = 0; - int32_t m_StartingLevel = 0; - int32_t m_Level = 0; - int32_t m_SoftdropCounter = 0; - - int32_t m_HighScore = 0; + Board m_board; + Tetromino m_active_tetromino; + Tetromino m_next_tetromino; + + int32_t m_tetromino_counters[Tetromino::id_count] {}; + int32_t m_score = 0; + int32_t m_line_counter = 0; + int32_t m_starting_level = 0; + int32_t m_level = 0; + int32_t m_softdrop_counter = 0; + + int32_t m_highscore = 0; }; diff --git a/src/games/tetris/Tetromino.cpp b/src/games/tetris/Tetromino.cpp index 9179d6d..97c8808 100644 --- a/src/games/tetris/Tetromino.cpp +++ b/src/games/tetris/Tetromino.cpp @@ -59,85 +59,101 @@ static const uint16_t s_left_aligned_bitmaps[7][4][4] = { }; -Tetromino::TetrominoId Tetromino::GetRandomId() { - static std::uniform_int_distribution s_Dist(0, tetromino_id_count-1); +Tetromino::TetrominoId Tetromino::GetRandomId() +{ + static std::uniform_int_distribution s_Dist(0, id_count-1); static std::mt19937 s_Rng((std::random_device()())); TetrominoId id = static_cast(s_Dist(s_Rng)); return id; } -Tetromino::Tetromino(uint16_t *board_bitmap) : - m_Id(GetRandomId()), - m_Pos{6, 20}, - m_Ori{0}, - m_BoardBitmap(board_bitmap) -{ -} -Tetromino::Tetromino(Board &board) : - Tetromino(board.m_Bitmap) +void +Tetromino::Reinit(uint16_t* board_bitmap) { + m_id = GetRandomId(); + m_pos = {6, 20}; + m_ori = {0}; + m_board_bitmap = board_bitmap; } -Tetromino::TetrominoId Tetromino::GetId() { - return m_Id; +Tetromino::TetrominoId +Tetromino::GetId() +{ + return m_id; } -BoardPos Tetromino::GetPos() { - return m_Pos; +BoardPos +Tetromino::GetPos() +{ + return m_pos; } -void Tetromino::GetBitmap(uint16_t *bitmap) { - GetBitmap(m_Id, m_Pos, m_Ori, bitmap); +void +Tetromino::GetBitmap(uint16_t* bitmap) +{ + GetBitmap(m_id, m_pos, m_ori, bitmap); } -bool Tetromino::IsCollisionWithBoard() { - bool is_collision = IsCollisionWithBoard(m_Id, m_Pos, m_Ori, m_BoardBitmap); +bool +Tetromino::IsCollisionWithBoard() +{ + bool is_collision = IsCollisionWithBoard(m_id, m_pos, m_ori, m_board_bitmap); return is_collision; } -void Tetromino::MaybeRotate(TetrominoRotation rotation) { - int32_t ori = (m_Ori + rotation) % 4; - if (!IsCollisionWithBoard(m_Id, m_Pos, ori, m_BoardBitmap)) { - m_Ori = ori; +void +Tetromino::MaybeRotate(TetrominoRotation rotation) +{ + int32_t ori = (m_ori + rotation) % 4; + if (!IsCollisionWithBoard(m_id, m_pos, ori, m_board_bitmap)) { + m_ori = ori; } } -void Tetromino::MaybeMoveHorizontally(TetrominoDirection direction) { - BoardPos pos = m_Pos; +void +Tetromino::MaybeMoveHorizontally(TetrominoDirection direction) +{ + BoardPos pos = m_pos; pos.x += static_cast(direction); - if (!IsCollisionWithBoard(m_Id, pos, m_Ori, m_BoardBitmap)) { - m_Pos.x = pos.x; + if (!IsCollisionWithBoard(m_id, pos, m_ori, m_board_bitmap)) { + m_pos.x = pos.x; } } -bool Tetromino::MaybeMoveDown() { - BoardPos pos = m_Pos; +bool +Tetromino::MaybeMoveDown() +{ + BoardPos pos = m_pos; pos.y -= 1; - if (!IsCollisionWithBoard(m_Id, pos, m_Ori, m_BoardBitmap)) { - m_Pos.y = pos.y; + if (!IsCollisionWithBoard(m_id, pos, m_ori, m_board_bitmap)) { + m_pos.y = pos.y; return true; } return false; } -void Tetromino::Draw() const { +void +Tetromino::Draw() +{ float world_width = 4.0f; float world_height = 3.0f; float tetromino_size_with_border = world_height / 20.0f; - float x0 = static_cast(m_Pos.x - 3); - float y0 = static_cast(m_Pos.y - 2); + float x0 = static_cast(m_pos.x - 3); + float y0 = static_cast(m_pos.y - 2); V2F32 world_pos = { ((world_width - tetromino_size_with_border*10) / 2.0f) + x0 * tetromino_size_with_border, y0 * tetromino_size_with_border }; - Tetromino::Draw(m_Id, m_Ori, world_pos, 1.0f); + Tetromino::Draw(m_id, m_ori, world_pos, 1.0f); } -bool Tetromino::IsCollisionWithBoard(TetrominoId id, BoardPos pos, int32_t ori, uint16_t *board_bitmap) { +bool +Tetromino::IsCollisionWithBoard(TetrominoId id, BoardPos pos, int32_t ori, uint16_t *board_bitmap) +{ uint16_t tetromino_bitmap[16]; GetBitmap(id, pos, ori, tetromino_bitmap); @@ -147,14 +163,18 @@ bool Tetromino::IsCollisionWithBoard(TetrominoId id, BoardPos pos, int32_t ori, return is_collision; } -void Tetromino::GetBitmap(TetrominoId id, BoardPos pos, int32_t ori, uint16_t *bitmap) { +void +Tetromino::GetBitmap(TetrominoId id, BoardPos pos, int32_t ori, uint16_t *bitmap) +{ size_t id_ = static_cast(id); uint64_t *src = (uint64_t*)s_left_aligned_bitmaps[id_][ori]; uint64_t *dest = (uint64_t*)bitmap; *dest = *src >> pos.x; } -Color Tetromino::GetColor(TetrominoId id) { +Color +Tetromino::GetColor(TetrominoId id) +{ using enum TetrominoId; Color color; @@ -179,7 +199,9 @@ Color Tetromino::GetColor(TetrominoId id) { return color; } -void Tetromino::Draw(TetrominoId id, int32_t ori, V2F32 pos, float scale) { +void +Tetromino::Draw(TetrominoId id, int32_t ori, V2F32 pos, float scale) +{ int32_t id_ = static_cast(id); float world_height = 3.0f; diff --git a/src/games/tetris/Tetromino.hpp b/src/games/tetris/Tetromino.hpp index 88f71f5..b40555b 100644 --- a/src/games/tetris/Tetromino.hpp +++ b/src/games/tetris/Tetromino.hpp @@ -15,8 +15,8 @@ public: l_piece, j_piece, i_piece, - tetromino_id_count, - tetromino_id_none, + id_count, + id_none, }; enum TetrominoRotation { @@ -31,21 +31,19 @@ public: public: - Tetromino() = delete; - Tetromino(Board &board); - Tetromino(uint16_t *board_bitmap); + void Reinit(uint16_t* board_bitmap); TetrominoId GetId(); BoardPos GetPos(); int32_t GetOri(); void GetBitmap(uint16_t *bitmap); - bool IsCollisionWithBoard(); // for last tetromino to check game over + bool IsCollisionWithBoard(); bool MaybeMoveDown(); void MaybeMoveHorizontally(TetrominoDirection direction); void MaybeRotate(TetrominoRotation rotation); - void Draw() const; + void Draw(); public: @@ -60,9 +58,9 @@ private: private: - TetrominoId m_Id; - BoardPos m_Pos; - int32_t m_Ori; - uint16_t *m_BoardBitmap; + TetrominoId m_id; + BoardPos m_pos; + int32_t m_ori; + uint16_t *m_board_bitmap; }; diff --git a/src/main.cpp b/src/main.cpp index 7fc7af6..7660628 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,14 +28,11 @@ Game::GameType DrawGameMenu() if (ImGui::Button("Tetris")) { type = Game::tetris; } - if (ImGui::Button("Snake")) { - type = Game::snake; - } if (ImGui::Button("Minesweeper")) { type = Game::minesweeper; } - if (ImGui::Button("Breakout")) { - type = Game::breakout; + if (ImGui::Button("Snake")) { + type = Game::snake; } ImGui::End(); -- cgit v1.2.3