From b7c4a2fa36b5a28612cdd57417c0e82eac73486f Mon Sep 17 00:00:00 2001 From: Diogo Cruz Diniz Date: Thu, 23 Apr 2026 22:26:43 +0100 Subject: [PATCH] feat: Grid af spawning --- src/dxd_math.cpp | 46 ++++++++++++++++++++++++++++++++++++++++-- src/dxd_math.hpp | 24 ++++++++++++++++++---- src/main.cpp | 12 ++++++++--- src/renderer.hpp | 15 ++++++++++++++ src/sim/af_spawner.cpp | 19 ++++++++++++++--- src/sim/af_spawner.hpp | 17 +++++++++++----- src/sim/aircraft.hpp | 2 +- src/sim/airfield.cpp | 8 +++----- src/sim/world.hpp | 3 +-- 9 files changed, 121 insertions(+), 25 deletions(-) diff --git a/src/dxd_math.cpp b/src/dxd_math.cpp index 82c416d..ed38a93 100644 --- a/src/dxd_math.cpp +++ b/src/dxd_math.cpp @@ -1,5 +1,7 @@ #include "dxd_math.hpp" +#include + vec2 operator+(vec2 const &v) { return { .x = v.x, .y = v.y }; @@ -40,6 +42,16 @@ bool operator>(vec2 const &a, vec2 const &b) return a.x > b.x && a.y > b.y; } +bool operator<(vec2i const &a, vec2i const &b) +{ + return a.x < b.x && a.y < b.y; +} + +bool operator>(vec2i const &a, vec2i const &b) +{ + return a.x > b.x && a.y > b.y; +} + float dot(vec2 const &a, vec2 const &b) { return a.x * b.x + a.y * b.y; @@ -76,7 +88,7 @@ vec2 max2(vec2 const &a, vec2 const &b) }; } -vec2 polar_to_vec2(const float angle, const float len) +vec2 polar_to_vec2(float const angle, float const len) { return { .x = len * sinf(angle), @@ -84,11 +96,16 @@ vec2 polar_to_vec2(const float angle, const float len) }; } -float vec2_angle(const vec2 v) +float vec2_angle(vec2 const v) { return atan2f(v.x, v.y); } +vec2 v2i_to_v2(vec2i const v) +{ + return { (float)v.x, (float)v.y }; +} + float normalize_angle(const float angle) { float a = angle; @@ -104,3 +121,28 @@ float normalize_angle_diff(const float diff) while (d < -M_PIf) d += 2*M_PIf; return d; } + +int rand_int(int const min, int const max) +{ + return SDL_rand(max - min) + min; +} + +float rand_float(float const min, float const max) +{ + return SDL_randf() * (max - min) + min; +} + +float rand_angle() +{ + return rand_float(0, 2*M_PIf); +} + +vec2i rand_v2i(vec2i const min, vec2i const max) +{ + return { rand_int(min.x, max.x), rand_int(min.y, max.y) }; +} + +vec2 rand_v2(vec2 const min, vec2 const max) +{ + return { rand_float(min.x, max.x), rand_float(min.y, max.y) }; +} diff --git a/src/dxd_math.hpp b/src/dxd_math.hpp index 5447d42..186644c 100644 --- a/src/dxd_math.hpp +++ b/src/dxd_math.hpp @@ -17,6 +17,7 @@ static const vec2 vec2_min = { -FLT_MAX, -FLT_MAX }; static const vec2i vec2i_zero = { 0, 0 }; static const vec2i vec2i_one = { 1, 1 }; +// vec2 operators vec2 operator+(vec2 const &v); vec2 operator-(vec2 const &v); vec2 operator+(vec2 const &a, vec2 const &b); @@ -26,15 +27,30 @@ vec2 operator/(vec2 const &a, float const &b); bool operator<(vec2 const &a, vec2 const &b); bool operator>(vec2 const &a, vec2 const &b); +// vec2i operators +bool operator<(vec2i const &a, vec2i const &b); +bool operator>(vec2i const &a, vec2i const &b); + +// vec2 functions float dot(vec2 const &a, vec2 const &b); float norm2(vec2 const &v); float norm(vec2 const &v); vec2 normalize(vec2 const &v); vec2 min2(vec2 const &a, vec2 const &b); vec2 max2(vec2 const &a, vec2 const &b); +vec2 polar_to_vec2(float const angle, float const len); +float vec2_angle(vec2 const v); -vec2 polar_to_vec2(const float angle, const float len); -float vec2_angle(const vec2 v); +// vec2i functions +vec2 v2i_to_v2(vec2i const v); -float normalize_angle(const float angle); -float normalize_angle_diff(const float diff); +// Angle functions +float normalize_angle(float const angle); +float normalize_angle_diff(float const diff); + +// Random generation functions +int rand_int(int const min, int const max); +float rand_float(float const min, float const max); +float rand_angle(); +vec2i rand_v2i(vec2i const min, vec2i const max); +vec2 rand_v2(vec2 const min, vec2 const max); diff --git a/src/main.cpp b/src/main.cpp index 23a5f1b..6eed697 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -45,7 +45,7 @@ int main(int argc, char *argv[]) dxd::Renderer renderer = dxd::Renderer(sdl_renderer, width, height); // World init - dxd::sim::World world = dxd::sim::World({ .x = 10, .y = 10 }); + dxd::sim::World world = dxd::sim::World(); world.add_obj(new dxd::sim::AFSpawner()); SDL_Event event; @@ -79,11 +79,17 @@ int main(int argc, char *argv[]) world.draw(&renderer); world.tick(1.0f / 60.0f); - // Usual test - renderer.color(64, 64, 64, 255); + // World axis + renderer.color(32, 32, 32, 255); renderer.line(-vec2_unity * 2000, vec2_unity * 2000); renderer.line(-vec2_unitx * 2000, vec2_unitx * 2000); + // Scale and position + vec2 center = renderer.get_camera_pos(); + float zoom = 100.0f/renderer.get_zoom(); + renderer.color(128, 128, 255, 255); + renderer.dbg_txt(0, 0, "(%0.1f, %0.1f) @%0.2f", center.x, center.y, zoom); + SDL_RenderPresent(sdl_renderer); SDL_Delay(1000 / 60); } diff --git a/src/renderer.hpp b/src/renderer.hpp index 3e5972e..2e890e1 100644 --- a/src/renderer.hpp +++ b/src/renderer.hpp @@ -60,6 +60,11 @@ public: _scale /= 1 + delta; } + vec2 get_camera_pos() + { + return _center; + } + float get_zoom() { return 1.0f / _scale; @@ -120,6 +125,16 @@ public: points[4] = points[0]; SDL_RenderLines(_sdl, points, 5); } + + void dbg_txt(float x, float y, const char *fmt, ...) + { + va_list args; + va_start(args, fmt); + + SDL_RenderDebugTextFormat(_sdl, x, y, fmt, args); + + va_end(args); + } }; } // namespace dxd diff --git a/src/sim/af_spawner.cpp b/src/sim/af_spawner.cpp index 8254808..72961a6 100644 --- a/src/sim/af_spawner.cpp +++ b/src/sim/af_spawner.cpp @@ -11,9 +11,22 @@ void dxd::sim::AFSpawner::tick(float timestep, World *world) _next_spawn = _MIN_SPAWN_DELAY + SDL_rand(_MAX_SPAWN_DELAY); - //Pos should spawn in a grid, check if free, and offset random from grid coord to look natural - vec2 pos = {(SDL_randf()-.5f)*2*60.0f, (SDL_randf()-.5f)*2*60.0f}; + vec2i base_pos; + //TODO: Set limiter + do + base_pos = rand_v2i({ -_GRID_BOUNDS, -_GRID_BOUNDS }, { _GRID_BOUNDS, _GRID_BOUNDS }); + while (_airfields.find(base_pos) != _airfields.end()); + + vec2 off = rand_v2({ -_GRID_JITTER, -_GRID_JITTER }, { _GRID_JITTER, _GRID_JITTER }); + vec2 pos = v2i_to_v2(base_pos) * _GRID_STRIDE + off; + Airfield *af = new Airfield(pos, _MIN_AF_TTL + SDL_rand(_MAX_AF_TTL), SDL_randf()*2*M_PIf); world->add_obj(af); - _airfields.push_back(af); + _airfields.emplace(base_pos, af); +} + +void dxd::sim::AFSpawner::draw(Renderer *rend) +{ + rend->color(0, 127, 0, 255); + rend->rect(vec2_zero, _SPAWN_BOUNDS*2); } diff --git a/src/sim/af_spawner.hpp b/src/sim/af_spawner.hpp index 0e1ffd5..5c92664 100644 --- a/src/sim/af_spawner.hpp +++ b/src/sim/af_spawner.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include "../dxd_math.hpp" #include "world_object.hpp" @@ -12,23 +13,29 @@ namespace dxd::sim class AFSpawner : public WorldObject { private: - std::vector _airfields; + std::map _airfields; int _next_spawn; + const int _SPAWN_BOUNDS = 150; + const int _GRID_STRIDE = 4; + const int _GRID_MARGIN = 5; + const int _GRID_BOUNDS = (_SPAWN_BOUNDS - _GRID_MARGIN * 2) / _GRID_STRIDE; + const float _GRID_JITTER = (float)_GRID_STRIDE * 0.4f; + const int _MIN_SPAWN_DELAY = 450; const int _MAX_SPAWN_DELAY = 3000; - const int _MIN_AF_TTL = 1200; - const int _MAX_AF_TTL = 6000; + const int _MIN_AF_TTL = 3000; + const int _MAX_AF_TTL = 9000; public: AFSpawner() { - _airfields = std::vector(); + _airfields = std::map(); _next_spawn = 1; } void tick(float timestep, World *world) override; - void draw(Renderer *rend) override { (void)rend; } + void draw(Renderer *rend) override; }; } // namespace dxd::sim diff --git a/src/sim/aircraft.hpp b/src/sim/aircraft.hpp index 1f7efd5..4bb08a7 100644 --- a/src/sim/aircraft.hpp +++ b/src/sim/aircraft.hpp @@ -17,7 +17,7 @@ private: const int _TRAIL_DELAY = 60; const int _TRAIL_DURATION = 420; - const float _MAX_TURN_RATE = 0.5f; + const float _MAX_TURN_RATE = 0.3f; public: Aircraft(vec2 position, float direction, float speed, vec2 target) diff --git a/src/sim/airfield.cpp b/src/sim/airfield.cpp index 61f1987..0b90370 100644 --- a/src/sim/airfield.cpp +++ b/src/sim/airfield.cpp @@ -14,12 +14,10 @@ void dxd::sim::Airfield::tick(float timestep, World *world) if (--_next_spawn == 0) { vec2 pos = _position + polar_to_vec2(_rw_heading, _WR_LENGTH+0.5); - //vec2 tgt = _position + polar_to_vec2(SDL_randf()*2*M_PIf, 30); - vec2 tgt = _position + polar_to_vec2(0, 30); - Aircraft *af = new Aircraft(pos, _rw_heading, 5.0f, tgt); + vec2 tgt = _position + polar_to_vec2(SDL_randf()*2*M_PIf, 30); + Aircraft *af = new Aircraft(pos, _rw_heading, 2.0f, tgt); world->add_obj(af); - //_next_spawn = _MIN_TAKEOFF_DELAY + SDL_rand(_MAX_TAKEOFF_DELAY - _MIN_TAKEOFF_DELAY); - _next_spawn = 99999999; + _next_spawn = _MIN_TAKEOFF_DELAY + SDL_rand(_MAX_TAKEOFF_DELAY - _MIN_TAKEOFF_DELAY); } } diff --git a/src/sim/world.hpp b/src/sim/world.hpp index f0eccc6..b08146c 100644 --- a/src/sim/world.hpp +++ b/src/sim/world.hpp @@ -13,13 +13,12 @@ class WorldObject; class World { private: - vec2 _size; std::vector _objs; std::vector _pending_removes; std::vector _pending_adds; public: - World(vec2 size) : _size(size) + World() { _objs = std::vector(); _pending_adds = std::vector();