aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/games/Game.cpp59
-rw-r--r--src/games/Game.hpp27
-rw-r--r--src/games/breakout/Breakout.cpp66
-rw-r--r--src/games/breakout/Breakout.hpp38
-rw-r--r--src/games/minesweeper/Minesweeper.cpp58
-rw-r--r--src/games/minesweeper/Minesweeper.hpp28
-rw-r--r--src/games/snake/Snake.cpp269
-rw-r--r--src/games/snake/Snake.hpp50
-rw-r--r--src/games/tetris/Board.cpp52
-rw-r--r--src/games/tetris/Board.hpp9
-rw-r--r--src/games/tetris/Tetris.cpp259
-rw-r--r--src/games/tetris/Tetris.hpp45
-rw-r--r--src/games/tetris/Tetromino.cpp100
-rw-r--r--src/games/tetris/Tetromino.hpp20
-rw-r--r--src/main.cpp7
15 files changed, 502 insertions, 585 deletions
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 <games/tetris/Tetris.hpp>
#include <games/snake/Snake.hpp>
#include <games/minesweeper/Minesweeper.hpp>
-#include <games/breakout/Breakout.hpp>
#include <assert.h>
#include <memory>
@@ -16,20 +15,16 @@ Game::Select(GameType type)
return nullptr;
} break;
- case tetris: {
- return std::make_unique<Tetris>();
+ case minesweeper: {
+ return std::make_unique<Minesweeper>();
} break;
case snake: {
return std::make_unique<Snake>();
} break;
- case minesweeper: {
- return std::make_unique<Minesweeper>();
- } break;
-
- case breakout: {
- return std::make_unique<Breakout>();
+ case tetris: {
+ return std::make_unique<Tetris>();
} 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 <vector>
-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<Game> Select(GameType type);
@@ -27,5 +31,16 @@ public:
Game() = default;
virtual ~Game() = default;
virtual bool Update(std::vector<SDL_Event>& 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 <games/breakout/Breakout.hpp>
-
-#include <imgui.h>
-
-
-bool
-Breakout::Update(std::vector<SDL_Event>& 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 <common/math.hpp>
-#include <common/shapes.hpp>
-#include <games/Game.hpp>
-
-
-struct Ball {
- V3F32 pos;
- float radius;
-};
-
-
-class Breakout : public Game {
- enum GameStatus {
- resume,
- pause,
- exit
- };
-
-public:
- Breakout() = default;
- bool Update(std::vector<SDL_Event> &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 <games/minesweeper/Minesweeper.hpp>
#include <renderer/Renderer.hpp>
@@ -117,31 +118,31 @@ Minesweeper::Update(std::vector<SDL_Event>& 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);
@@ -302,22 +303,6 @@ Minesweeper::ScreenPosToViewPos(V2F32 screen_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()
{
ImGui::Begin("MinesweeperStart");
@@ -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 <array>
-namespace std {
- template <>
- struct hash<V2ST> {
- size_t operator()(const V2ST& v) const {
- size_t h1 = hash<size_t>{}(v.x);
- size_t h2 = hash<size_t>{}(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 <chrono>
#include <games/snake/Snake.hpp>
+#include <renderer/Renderer.hpp>
#include <imgui.h>
+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<int32_t>(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<int32_t>(0, m_map_width*m_map_height - 3);
SpawnFood();
-}
-
-bool Snake::Update(std::vector<SDL_Event> &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<SDL_Event> &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<int32_t>::param_type(0, bit0_count_total - 1));
- int32_t bit0_index = m_Dist(m_Rng);
+ m_dist.param(std::uniform_int_distribution<int32_t>::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<SDL_Event> &events) override;
+ bool Update(std::vector<SDL_Event>& 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<int32_t> 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<int32_t> 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 <games/tetris/Tetromino.hpp>
#include <games/tetris/Board.hpp>
+#include <games/tetris/Tetromino.hpp>
#include <renderer/Renderer.hpp>
-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 <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();
}
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 <games/tetris/Board.hpp>
-enum class TetrisRunningState {
- Resume,
- Pause,
- GameOver,
- Restart,
- Exit
-};
-
-
class Tetris : public Game {
public:
- Tetris();
+ Tetris() = default;
bool Update(std::vector<SDL_Event> &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<int> s_Dist(0, tetromino_id_count-1);
+Tetromino::TetrominoId Tetromino::GetRandomId()
+{
+ static std::uniform_int_distribution<int> s_Dist(0, id_count-1);
static std::mt19937 s_Rng((std::random_device()()));
TetrominoId id = static_cast<TetrominoId>(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<int32_t>(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<float>(m_Pos.x - 3);
- float y0 = static_cast<float>(m_Pos.y - 2);
+ float x0 = static_cast<float>(m_pos.x - 3);
+ float y0 = static_cast<float>(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<size_t>(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<int32_t>(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();