From d1ff0e6a158e84411f119057e16501fe03ba25c5 Mon Sep 17 00:00:00 2001 From: Diogo Cruz Diniz Date: Thu, 23 Apr 2026 23:18:06 +0100 Subject: [PATCH] feat: Primitive airfield navigation --- src/sim/af_spawner.cpp | 50 +++++++++++++++++++++++++++++++++--------- src/sim/af_spawner.hpp | 8 ++++++- src/sim/aircraft.hpp | 2 +- src/sim/airfield.cpp | 15 ++++++++----- src/sim/airfield.hpp | 16 +++++++++----- 5 files changed, 69 insertions(+), 22 deletions(-) diff --git a/src/sim/af_spawner.cpp b/src/sim/af_spawner.cpp index 13532f1..d4489c8 100644 --- a/src/sim/af_spawner.cpp +++ b/src/sim/af_spawner.cpp @@ -2,17 +2,10 @@ #include -void dxd::sim::AFSpawner::tick(float timestep, World *world) +void dxd::sim::AFSpawner::spawn_airfield(World *world) { - (void)timestep; - - if (--_next_spawn != 0) - return; - - _next_spawn = _MIN_SPAWN_DELAY + SDL_rand(_MAX_SPAWN_DELAY); - vec2i base_pos; - //TODO: Set limiter + //TODO: Iter limiter do base_pos = rand_v2i({ -_GRID_BOUNDS, -_GRID_BOUNDS }, { _GRID_BOUNDS, _GRID_BOUNDS }); while (_airfields.find(base_pos) != _airfields.end()); @@ -20,13 +13,50 @@ void dxd::sim::AFSpawner::tick(float timestep, World *world) 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); + Airfield *af = new Airfield(this, pos, _MIN_AF_TTL + SDL_rand(_MAX_AF_TTL), SDL_randf()*2*M_PIf); world->add_obj(af); _airfields.emplace(base_pos, af); } +void dxd::sim::AFSpawner::tick(float timestep, World *world) +{ + (void)timestep; + + if (_next_spawn == -1) //Init + { + spawn_airfield(world); + spawn_airfield(world); + _next_spawn = _MIN_SPAWN_DELAY; + return; + } + + if (--_next_spawn != 0) + return; + + _next_spawn = _MIN_SPAWN_DELAY + SDL_rand(_MAX_SPAWN_DELAY); + + spawn_airfield(world); +} + void dxd::sim::AFSpawner::draw(Renderer *rend) { rend->color(0, 127, 0); rend->rect(vec2_zero, _SPAWN_BOUNDS*2); } + +dxd::sim::Airfield *dxd::sim::AFSpawner::get_random_airfield(Airfield *exclude) +{ + int count = (int)_airfields.size(); + Airfield *af = exclude; + + //TODO: Iter limiter + do + { + int sel = rand_int(0, count); + auto it = _airfields.begin(); + for (; it != _airfields.end() && sel; ++it, --sel); + af = it->second; + } while(af == exclude); + + return af; +} diff --git a/src/sim/af_spawner.hpp b/src/sim/af_spawner.hpp index 5c92664..afc071c 100644 --- a/src/sim/af_spawner.hpp +++ b/src/sim/af_spawner.hpp @@ -10,6 +10,8 @@ namespace dxd::sim { +class Airfield; + class AFSpawner : public WorldObject { private: @@ -27,15 +29,19 @@ private: const int _MIN_AF_TTL = 3000; const int _MAX_AF_TTL = 9000; + void spawn_airfield(World *world); + public: AFSpawner() { _airfields = std::map(); - _next_spawn = 1; + _next_spawn = -1; } void tick(float timestep, World *world) override; void draw(Renderer *rend) override; + + Airfield *get_random_airfield(Airfield *exclude); }; } // namespace dxd::sim diff --git a/src/sim/aircraft.hpp b/src/sim/aircraft.hpp index 520dc15..538173b 100644 --- a/src/sim/aircraft.hpp +++ b/src/sim/aircraft.hpp @@ -16,7 +16,7 @@ private: int _trail_cooldown; const int _TRAIL_DELAY = 120; - const int _TRAIL_DURATION = 420; + const int _TRAIL_DURATION = 600; const float _MAX_TURN_RATE = 0.3f; const float _SPD_TO_KTS = 60.0f; diff --git a/src/sim/airfield.cpp b/src/sim/airfield.cpp index 977c2d3..0937aa3 100644 --- a/src/sim/airfield.cpp +++ b/src/sim/airfield.cpp @@ -8,15 +8,20 @@ void dxd::sim::Airfield::tick(float timestep, World *world) if (--_ttl == 0) { world->remove_obj(this); + //TODO: Free space in af_spawner return; } 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); - Aircraft *af = new Aircraft(pos, _rw_heading, 2.0f, tgt); + vec2 pos = _position + polar_to_vec2(_rw_heading, _RW_LENGTH+0.5); + + Airfield *target = _parent->get_random_airfield(this); + vec2 tgt_pos = target->get_position(); + + Aircraft *af = new Aircraft(pos, _rw_heading, 2.0f, tgt_pos); world->add_obj(af); + _next_spawn = _MIN_TAKEOFF_DELAY + SDL_rand(_MAX_TAKEOFF_DELAY - _MIN_TAKEOFF_DELAY); } } @@ -28,7 +33,7 @@ void dxd::sim::Airfield::draw(Renderer *rend) rend->diamond(_position, 5); rend->color(64, 64, 255); - vec2 a = _position + polar_to_vec2(_rw_heading, +_WR_LENGTH); - vec2 b = _position + polar_to_vec2(_rw_heading, -_WR_LENGTH); + vec2 a = _position + polar_to_vec2(_rw_heading, +_RW_LENGTH); + vec2 b = _position + polar_to_vec2(_rw_heading, -_RW_LENGTH); rend->line(a, b); } diff --git a/src/sim/airfield.hpp b/src/sim/airfield.hpp index 46567df..6786fef 100644 --- a/src/sim/airfield.hpp +++ b/src/sim/airfield.hpp @@ -4,29 +4,35 @@ #include "../dxd_math.hpp" #include "world_object.hpp" +#include "af_spawner.hpp" namespace dxd::sim { +class AFSpawner; + class Airfield : public WorldObject { private: + AFSpawner *_parent; vec2 _position; int _ttl; int _next_spawn; float _rw_heading; - const int _MIN_TAKEOFF_DELAY = 240; - const int _MAX_TAKEOFF_DELAY = 600; - const int _WR_LENGTH = 6; + int const _MIN_TAKEOFF_DELAY = 600; + int const _MAX_TAKEOFF_DELAY = 3000; + int const _RW_LENGTH = 6; public: - Airfield(vec2 position, int ttl, float rw_heading) - : _position(position), _ttl(ttl), _rw_heading(rw_heading) + Airfield(AFSpawner *parent, vec2 position, int ttl, float rw_heading) + : _parent(parent), _position(position), _ttl(ttl), _rw_heading(rw_heading) { _next_spawn = _MIN_TAKEOFF_DELAY; } + vec2 get_position() { return _position; } + void tick(float timestep, World *world) override; void draw(Renderer *rend) override; };