From 8e89f1bf70134a328f15800e42e65359378a539c Mon Sep 17 00:00:00 2001 From: Grant Horner Date: Tue, 2 Dec 2025 17:14:40 -0500 Subject: [PATCH] refactor viewport --- main.cpp | 66 +++++++++++++++++++++++--------------------------------- types.h | 36 ++++++++++++++++++++++++++++--- 2 files changed, 60 insertions(+), 42 deletions(-) diff --git a/main.cpp b/main.cpp index 0b65279..074813c 100644 --- a/main.cpp +++ b/main.cpp @@ -9,24 +9,15 @@ #include "spawner.h" #include "types.h" -float screen_width = 800; -float screen_height = 600; - -float padding = 50; -float level_width = screen_width - padding * 2; -float level_height = screen_height - padding * 2; -float level_left = padding; -float level_top = padding; -float level_right = level_width + padding; -float level_bottom = level_height + padding; +Viewport viewport{800, 600}; Rectangle walls[] = {}; float player_width = 50; Player player = { .rect = { - .x = level_width / 2 - player_width / 2, - .y = level_height / 2 - player_width / 2, + .x = viewport.level_width / 2 - player_width / 2, + .y = viewport.level_height / 2 - player_width / 2, .width = player_width, .height = player_width, }, @@ -61,8 +52,8 @@ bool Player::is_invulnerable(const double now) const noexcept { void Player::move(const Vector2 delta) { const auto [next_x, next_y] = Vector2Clamp( Vector2Add({this->rect.x, this->rect.y}, delta), - {level_left, level_top}, - Vector2Subtract({level_right, level_bottom}, {this->rect.width, this->rect.height}) + {viewport.level_left, viewport.level_top}, + Vector2Subtract({viewport.level_right, viewport.level_bottom}, {this->rect.width, this->rect.height}) ); bool collided = false; @@ -94,24 +85,26 @@ struct EnemySpawner final : Spawner { void spawn() override { const auto num = Rng::generate(); - const auto starting_x = Rng::generate(static_cast(level_left), static_cast(level_right)); - const auto starting_y = Rng::generate(static_cast(level_top), static_cast(level_bottom)); + const auto starting_x = Rng::generate(static_cast(viewport.level_left), + static_cast(viewport.level_right)); + const auto starting_y = Rng::generate(static_cast(viewport.level_top), + static_cast(viewport.level_bottom)); for (auto &[center, radius, speed, alive]: this->values) { if (alive) continue; alive = true; radius = enemy_radius; if (num < 0.25) { - center = {.x = starting_x, .y = level_top}; + center = {.x = starting_x, .y = viewport.level_top}; } else if (0.25 <= num && num < 0.5) { center = { - .x = starting_x, .y = level_bottom + .x = starting_x, .y = viewport.level_bottom }; } else if (0.5 <= num && num < 0.75) { - center = {.x = level_left, .y = starting_y}; + center = {.x = viewport.level_left, .y = starting_y}; } else { center = { - .x = level_right, .y = starting_y + .x = viewport.level_right, .y = starting_y }; } @@ -130,8 +123,8 @@ struct ItemSpawner final : Spawner { void spawn() override { const auto item_type = static_cast(Rng::generate(ITEM_TYPE_COUNT)); - const auto x = Rng::generate(static_cast(level_left), static_cast(level_right)); - const auto y = Rng::generate(static_cast(level_top), static_cast(level_bottom)); + const auto x = Rng::generate(static_cast(viewport.level_left), static_cast(viewport.level_right)); + const auto y = Rng::generate(static_cast(viewport.level_top), static_cast(viewport.level_bottom)); for (auto &item: this->values) { if (item.active) continue; @@ -220,16 +213,9 @@ int main() { while (!WindowShouldClose()) { constexpr double item_pickup_message_duration = 3; - float dt_secs = GetFrameTime(); + // float dt_secs = GetFrameTime(); if (IsWindowResized()) { - screen_height = static_cast(GetScreenHeight()); - screen_width = static_cast(GetScreenWidth()); - level_width = screen_width - padding * 2; - level_height = screen_height - padding * 2; - level_left = padding; - level_top = padding; - level_right = level_width + padding; - level_bottom = level_height + padding; + viewport = {static_cast(GetScreenWidth()), static_cast(GetScreenHeight())}; } @@ -265,7 +251,8 @@ int main() { BeginDrawing(); ClearBackground(GRAY); - DrawRectangle(50, 50, static_cast(level_width), static_cast(level_height), RAYWHITE); + DrawRectangle(50, 50, static_cast(viewport.level_width), static_cast(viewport.level_height), + RAYWHITE); DrawRectangleRec(player.rect, player.is_invulnerable(now) ? GOLD : BLUE); for (const auto wall: walls) { @@ -283,8 +270,8 @@ int main() { enemy.center = Vector2MoveTowards(enemy.center, player.center(), enemy.speed); DrawCircleV(enemy.center, enemy.radius, RED); - if (enemy.center.x < level_left || level_right < enemy.center.x || - enemy.center.y < level_top || level_bottom < enemy.center.y) { + if (enemy.center.x < viewport.level_left || viewport.level_right < enemy.center.x || + enemy.center.y < viewport.level_top || viewport.level_bottom < enemy.center.y) { enemy.alive = false; } @@ -328,21 +315,22 @@ int main() { } }); - const int text_left = static_cast(level_left) + 10; + const int text_left = static_cast(viewport.level_left) + 10; - DrawRectangle(static_cast(level_left), static_cast(level_height) - 110, 200, 110, + DrawRectangle(static_cast(viewport.level_left), static_cast(viewport.level_height) - 110, 200, 110, {130, 130, 130, 100}); std::format_to(std::back_inserter(score_text_buffer), "Score: {}", score); - DrawText(score_text_buffer.c_str(), text_left, static_cast(level_height) - 100, 20, BLACK); + DrawText(score_text_buffer.c_str(), text_left, static_cast(viewport.level_height) - 100, 20, BLACK); score_text_buffer.clear(); std::format_to(std::back_inserter(lives_text_buffer), "Lives: {}", player.lives); - DrawText(lives_text_buffer.c_str(), text_left, static_cast(level_height) - 75, 20, BLACK); + DrawText(lives_text_buffer.c_str(), text_left, static_cast(viewport.level_height) - 75, 20, BLACK); lives_text_buffer.clear(); if (now < item_last_picked_up + item_pickup_message_duration && !item_pickup_text_buffer.empty()) { - DrawText(item_pickup_text_buffer.c_str(), text_left, static_cast(level_height) - 50, 20, BLACK); + DrawText(item_pickup_text_buffer.c_str(), text_left, static_cast(viewport.level_height) - 50, 20, + BLACK); } if (item_last_picked_up + item_pickup_message_duration <= now && !item_pickup_text_buffer.empty()) { diff --git a/types.h b/types.h index e623f39..78e34a9 100644 --- a/types.h +++ b/types.h @@ -60,11 +60,11 @@ enum ItemType { ITEM_TYPE_COUNT }; -template <> +template<> struct std::formatter : std::formatter { bool title_case = false; - constexpr auto parse(std::format_parse_context& ctx) { + constexpr auto parse(std::format_parse_context &ctx) { auto it = ctx.begin(); if (it == ctx.end()) return it; @@ -76,7 +76,7 @@ struct std::formatter : std::formatter { return it; } - auto format(const ItemType& item_type, std::format_context& ctx) const { + auto format(const ItemType &item_type, std::format_context &ctx) const { std::string_view item_type_str; switch (item_type) { case TEARS_UP: @@ -122,3 +122,33 @@ struct Item { assert(0 && "Unreachable."); } }; + +struct Viewport { + Viewport() = default; + + Viewport(const float screen_width, const float screen_height) + : screen_width(screen_width), + screen_height(screen_height), + padding(50), + level_width(screen_width - padding * 2), + level_height(screen_height - padding * 2), + level_left(padding), + level_top(padding), + level_right(level_width + padding), + level_bottom(level_height + padding) { + } + + Viewport& operator=(const Viewport &other) = default; + + float screen_width; + float screen_height; + + float padding; + + float level_width; + float level_height; + float level_left; + float level_top; + float level_right; + float level_bottom; +};