Add per-level wind atmosphere property

WIND directive in .lvl files sets a constant horizontal force (px/s^2)
that pushes entities, projectiles, and particles. Positive is rightward.

Wind is applied as acceleration in physics_update() (halved on ground),
directly to projectile and particle velocities, and as a gentle position
drift on flyers. Entities with gravity_scale=0 (drones, spacecraft) are
unaffected. Levels default to no wind when the directive is absent.
This commit is contained in:
Thomas
2026-03-01 17:13:01 +00:00
parent cdba479ced
commit 6c4b076c68
11 changed files with 56 additions and 5 deletions

View File

@@ -82,6 +82,7 @@ void particle_emit(const ParticleBurst *b) {
void particle_update(float dt) {
float gravity = physics_get_gravity();
float wind = physics_get_wind();
for (int i = 0; i < MAX_PARTICLES; i++) {
Particle *p = &s_particles[i];
@@ -96,6 +97,11 @@ void particle_update(float dt) {
/* Apply gravity */
p->vel.y += gravity * p->gravity_scale * dt;
/* Apply wind (reuse gravity_scale as environmental-force scale) */
if (wind != 0.0f && p->gravity_scale > 0.0f) {
p->vel.x += wind * p->gravity_scale * dt;
}
/* Apply drag */
if (p->drag > 0) {
float factor = 1.0f - p->drag * dt;

View File

@@ -4,9 +4,11 @@
#include <math.h>
static float s_gravity = DEFAULT_GRAVITY;
static float s_wind = 0.0f;
void physics_init(void) {
s_gravity = DEFAULT_GRAVITY;
s_wind = 0.0f;
}
void physics_set_gravity(float gravity) {
@@ -17,6 +19,14 @@ float physics_get_gravity(void) {
return s_gravity;
}
void physics_set_wind(float wind) {
s_wind = wind;
}
float physics_get_wind(void) {
return s_wind;
}
static void resolve_tilemap_x(Body *body, const Tilemap *map) {
if (!map) return;
@@ -102,6 +112,12 @@ void physics_update(Body *body, float dt, const Tilemap *map) {
/* Apply gravity */
body->vel.y += s_gravity * body->gravity_scale * dt;
/* Apply wind — halved on ground (friction counteracts) */
if (s_wind != 0.0f && body->gravity_scale > 0.0f) {
float wind_factor = body->on_ground ? 0.5f : 1.0f;
body->vel.x += s_wind * body->gravity_scale * wind_factor * dt;
}
/* Clamp fall speed */
if (body->vel.y > MAX_FALL_SPEED) {
body->vel.y = MAX_FALL_SPEED;

View File

@@ -25,6 +25,10 @@ void physics_init(void);
void physics_set_gravity(float gravity);
float physics_get_gravity(void);
/* Set / get the current horizontal wind force (pixels/s^2, +=right) */
void physics_set_wind(float wind);
float physics_get_wind(void);
/* Move body, apply gravity, resolve against tilemap */
void physics_update(Body *body, float dt, const Tilemap *map);

View File

@@ -85,6 +85,8 @@ bool tilemap_load(Tilemap *map, const char *path, SDL_Renderer *renderer) {
map->player_spawn = vec2(sx * TILE_SIZE, sy * TILE_SIZE);
} else if (strncmp(line, "GRAVITY ", 8) == 0) {
sscanf(line + 8, "%f", &map->gravity);
} else if (strncmp(line, "WIND ", 5) == 0) {
sscanf(line + 5, "%f", &map->wind);
} else if (strncmp(line, "TILEDEF ", 8) == 0) {
int id, tx, ty;
uint32_t flags;

View File

@@ -50,6 +50,7 @@ typedef struct Tilemap {
char tileset_path[ASSET_PATH_MAX]; /* tileset file path */
Vec2 player_spawn;
float gravity; /* level gravity (px/s^2), 0 = use default */
float wind; /* horizontal wind force (px/s^2), +=right */
char music_path[ASSET_PATH_MAX]; /* level music file path */
SDL_Color bg_color; /* background clear color */
bool has_bg_color; /* true if BG_COLOR was set */