diff options
Diffstat (limited to 'src/games')
| -rw-r--r-- | src/games/Game.cpp | 59 | ||||
| -rw-r--r-- | src/games/Game.hpp | 27 | ||||
| -rw-r--r-- | src/games/breakout/Breakout.cpp | 66 | ||||
| -rw-r--r-- | src/games/breakout/Breakout.hpp | 38 | ||||
| -rw-r--r-- | src/games/minesweeper/Minesweeper.cpp | 58 | ||||
| -rw-r--r-- | src/games/minesweeper/Minesweeper.hpp | 28 | ||||
| -rw-r--r-- | src/games/snake/Snake.cpp | 269 | ||||
| -rw-r--r-- | src/games/snake/Snake.hpp | 50 | ||||
| -rw-r--r-- | src/games/tetris/Board.cpp | 52 | ||||
| -rw-r--r-- | src/games/tetris/Board.hpp | 9 | ||||
| -rw-r--r-- | src/games/tetris/Tetris.cpp | 259 | ||||
| -rw-r--r-- | src/games/tetris/Tetris.hpp | 45 | ||||
| -rw-r--r-- | src/games/tetris/Tetromino.cpp | 100 | ||||
| -rw-r--r-- | src/games/tetris/Tetromino.hpp | 20 | 
14 files changed, 500 insertions, 580 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;  };  | 
