feat: Grid af spawning

This commit is contained in:
2026-04-23 22:26:43 +01:00
parent 153fb762af
commit b7c4a2fa36
9 changed files with 121 additions and 25 deletions

View File

@@ -1,5 +1,7 @@
#include "dxd_math.hpp" #include "dxd_math.hpp"
#include <SDL3/SDL.h>
vec2 operator+(vec2 const &v) vec2 operator+(vec2 const &v)
{ {
return { .x = v.x, .y = v.y }; 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; 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) float dot(vec2 const &a, vec2 const &b)
{ {
return a.x * b.x + a.y * b.y; 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 { return {
.x = len * sinf(angle), .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); 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 normalize_angle(const float angle)
{ {
float a = angle; float a = angle;
@@ -104,3 +121,28 @@ float normalize_angle_diff(const float diff)
while (d < -M_PIf) d += 2*M_PIf; while (d < -M_PIf) d += 2*M_PIf;
return d; 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) };
}

View File

@@ -17,6 +17,7 @@ static const vec2 vec2_min = { -FLT_MAX, -FLT_MAX };
static const vec2i vec2i_zero = { 0, 0 }; static const vec2i vec2i_zero = { 0, 0 };
static const vec2i vec2i_one = { 1, 1 }; static const vec2i vec2i_one = { 1, 1 };
// vec2 operators
vec2 operator+(vec2 const &v); vec2 operator+(vec2 const &v);
vec2 operator-(vec2 const &v); vec2 operator-(vec2 const &v);
vec2 operator+(vec2 const &a, vec2 const &b); 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);
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 dot(vec2 const &a, vec2 const &b);
float norm2(vec2 const &v); float norm2(vec2 const &v);
float norm(vec2 const &v); float norm(vec2 const &v);
vec2 normalize(vec2 const &v); vec2 normalize(vec2 const &v);
vec2 min2(vec2 const &a, vec2 const &b); vec2 min2(vec2 const &a, vec2 const &b);
vec2 max2(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); // vec2i functions
float vec2_angle(const vec2 v); vec2 v2i_to_v2(vec2i const v);
float normalize_angle(const float angle); // Angle functions
float normalize_angle_diff(const float diff); 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);

View File

@@ -45,7 +45,7 @@ int main(int argc, char *argv[])
dxd::Renderer renderer = dxd::Renderer(sdl_renderer, width, height); dxd::Renderer renderer = dxd::Renderer(sdl_renderer, width, height);
// World init // 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()); world.add_obj(new dxd::sim::AFSpawner());
SDL_Event event; SDL_Event event;
@@ -79,11 +79,17 @@ int main(int argc, char *argv[])
world.draw(&renderer); world.draw(&renderer);
world.tick(1.0f / 60.0f); world.tick(1.0f / 60.0f);
// Usual test // World axis
renderer.color(64, 64, 64, 255); renderer.color(32, 32, 32, 255);
renderer.line(-vec2_unity * 2000, vec2_unity * 2000); renderer.line(-vec2_unity * 2000, vec2_unity * 2000);
renderer.line(-vec2_unitx * 2000, vec2_unitx * 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_RenderPresent(sdl_renderer);
SDL_Delay(1000 / 60); SDL_Delay(1000 / 60);
} }

View File

@@ -60,6 +60,11 @@ public:
_scale /= 1 + delta; _scale /= 1 + delta;
} }
vec2 get_camera_pos()
{
return _center;
}
float get_zoom() float get_zoom()
{ {
return 1.0f / _scale; return 1.0f / _scale;
@@ -120,6 +125,16 @@ public:
points[4] = points[0]; points[4] = points[0];
SDL_RenderLines(_sdl, points, 5); 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 } // namespace dxd

View File

@@ -11,9 +11,22 @@ void dxd::sim::AFSpawner::tick(float timestep, World *world)
_next_spawn = _MIN_SPAWN_DELAY + SDL_rand(_MAX_SPAWN_DELAY); _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 vec2i base_pos;
vec2 pos = {(SDL_randf()-.5f)*2*60.0f, (SDL_randf()-.5f)*2*60.0f}; //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); Airfield *af = new Airfield(pos, _MIN_AF_TTL + SDL_rand(_MAX_AF_TTL), SDL_randf()*2*M_PIf);
world->add_obj(af); 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);
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <map>
#include "../dxd_math.hpp" #include "../dxd_math.hpp"
#include "world_object.hpp" #include "world_object.hpp"
@@ -12,23 +13,29 @@ namespace dxd::sim
class AFSpawner : public WorldObject class AFSpawner : public WorldObject
{ {
private: private:
std::vector<Airfield*> _airfields; std::map<vec2i, Airfield*> _airfields;
int _next_spawn; 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 _MIN_SPAWN_DELAY = 450;
const int _MAX_SPAWN_DELAY = 3000; const int _MAX_SPAWN_DELAY = 3000;
const int _MIN_AF_TTL = 1200; const int _MIN_AF_TTL = 3000;
const int _MAX_AF_TTL = 6000; const int _MAX_AF_TTL = 9000;
public: public:
AFSpawner() AFSpawner()
{ {
_airfields = std::vector<Airfield*>(); _airfields = std::map<vec2i, Airfield*>();
_next_spawn = 1; _next_spawn = 1;
} }
void tick(float timestep, World *world) override; void tick(float timestep, World *world) override;
void draw(Renderer *rend) override { (void)rend; } void draw(Renderer *rend) override;
}; };
} // namespace dxd::sim } // namespace dxd::sim

View File

@@ -17,7 +17,7 @@ private:
const int _TRAIL_DELAY = 60; const int _TRAIL_DELAY = 60;
const int _TRAIL_DURATION = 420; const int _TRAIL_DURATION = 420;
const float _MAX_TURN_RATE = 0.5f; const float _MAX_TURN_RATE = 0.3f;
public: public:
Aircraft(vec2 position, float direction, float speed, vec2 target) Aircraft(vec2 position, float direction, float speed, vec2 target)

View File

@@ -14,12 +14,10 @@ void dxd::sim::Airfield::tick(float timestep, World *world)
if (--_next_spawn == 0) if (--_next_spawn == 0)
{ {
vec2 pos = _position + polar_to_vec2(_rw_heading, _WR_LENGTH+0.5); 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(SDL_randf()*2*M_PIf, 30);
vec2 tgt = _position + polar_to_vec2(0, 30); Aircraft *af = new Aircraft(pos, _rw_heading, 2.0f, tgt);
Aircraft *af = new Aircraft(pos, _rw_heading, 5.0f, tgt);
world->add_obj(af); world->add_obj(af);
//_next_spawn = _MIN_TAKEOFF_DELAY + SDL_rand(_MAX_TAKEOFF_DELAY - _MIN_TAKEOFF_DELAY); _next_spawn = _MIN_TAKEOFF_DELAY + SDL_rand(_MAX_TAKEOFF_DELAY - _MIN_TAKEOFF_DELAY);
_next_spawn = 99999999;
} }
} }

View File

@@ -13,13 +13,12 @@ class WorldObject;
class World class World
{ {
private: private:
vec2 _size;
std::vector<WorldObject*> _objs; std::vector<WorldObject*> _objs;
std::vector<WorldObject*> _pending_removes; std::vector<WorldObject*> _pending_removes;
std::vector<WorldObject*> _pending_adds; std::vector<WorldObject*> _pending_adds;
public: public:
World(vec2 size) : _size(size) World()
{ {
_objs = std::vector<WorldObject*>(); _objs = std::vector<WorldObject*>();
_pending_adds = std::vector<WorldObject*>(); _pending_adds = std::vector<WorldObject*>();