Compare commits

..

2 Commits

Author SHA1 Message Date
8e89f1bf70 refactor viewport 2025-12-02 19:40:54 -05:00
d4f69278d9 refactor speed, invulnerability; refactor move to use Vec2 2025-12-02 17:09:57 -05:00
2 changed files with 61 additions and 42 deletions

View File

@@ -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<Enemy, 100> {
void spawn() override {
const auto num = Rng::generate();
const auto starting_x = Rng::generate(static_cast<int>(level_left), static_cast<int>(level_right));
const auto starting_y = Rng::generate(static_cast<int>(level_top), static_cast<int>(level_bottom));
const auto starting_x = Rng::generate(static_cast<int>(viewport.level_left),
static_cast<int>(viewport.level_right));
const auto starting_y = Rng::generate(static_cast<int>(viewport.level_top),
static_cast<int>(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<Item, 100> {
void spawn() override {
const auto item_type = static_cast<ItemType>(Rng::generate(ITEM_TYPE_COUNT));
const auto x = Rng::generate(static_cast<int>(level_left), static_cast<int>(level_right));
const auto y = Rng::generate(static_cast<int>(level_top), static_cast<int>(level_bottom));
const auto x = Rng::generate(static_cast<int>(viewport.level_left), static_cast<int>(viewport.level_right));
const auto y = Rng::generate(static_cast<int>(viewport.level_top), static_cast<int>(viewport.level_bottom));
for (auto &item: this->values) {
if (item.active) continue;
@@ -217,18 +210,12 @@ int main() {
std::string item_pickup_text_buffer;
item_pickup_text_buffer.reserve(64);
double item_last_picked_up = 0;
double item_pickup_message_duration = 3;
while (!WindowShouldClose()) {
constexpr double item_pickup_message_duration = 3;
// float dt_secs = GetFrameTime();
if (IsWindowResized()) {
screen_height = static_cast<float>(GetScreenHeight());
screen_width = static_cast<float>(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<float>(GetScreenWidth()), static_cast<float>(GetScreenHeight())};
}
@@ -264,7 +251,8 @@ int main() {
BeginDrawing();
ClearBackground(GRAY);
DrawRectangle(50, 50, static_cast<int>(level_width), static_cast<int>(level_height), RAYWHITE);
DrawRectangle(50, 50, static_cast<int>(viewport.level_width), static_cast<int>(viewport.level_height),
RAYWHITE);
DrawRectangleRec(player.rect, player.is_invulnerable(now) ? GOLD : BLUE);
for (const auto wall: walls) {
@@ -282,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;
}
@@ -327,21 +315,22 @@ int main() {
}
});
const int text_left = static_cast<int>(level_left) + 10;
const int text_left = static_cast<int>(viewport.level_left) + 10;
DrawRectangle(static_cast<int>(level_left), static_cast<int>(level_height) - 110, 200, 110,
DrawRectangle(static_cast<int>(viewport.level_left), static_cast<int>(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<int>(level_height) - 100, 20, BLACK);
DrawText(score_text_buffer.c_str(), text_left, static_cast<int>(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<int>(level_height) - 75, 20, BLACK);
DrawText(lives_text_buffer.c_str(), text_left, static_cast<int>(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<int>(level_height) - 50, 20, BLACK);
DrawText(item_pickup_text_buffer.c_str(), text_left, static_cast<int>(viewport.level_height) - 50, 20,
BLACK);
}
if (item_last_picked_up + item_pickup_message_duration <= now && !item_pickup_text_buffer.empty()) {

30
types.h
View File

@@ -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;
};