diff options
Diffstat (limited to 'src/games/snake')
| -rw-r--r-- | src/games/snake/Snake.cpp | 269 | ||||
| -rw-r--r-- | src/games/snake/Snake.hpp | 50 |
2 files changed, 163 insertions, 156 deletions
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; }; |
