Add height zones, jetpack boost particles, and TigerStyle guidelines
Level generator: add vertical variety with tall levels (46 tiles). Segment generators accept ground_row parameter, SEG_CLIMB connects height zones, transitions inherit predecessor ground row to prevent walkability gaps. Climb segments respect traversal direction. Jetpack boost: add blue flame particles during dash (burst + trail) and continuous idle glow from player back while boost timer is active. Camera: add 30px vertical look-ahead when player velocity exceeds 50 px/s. Fix flame vent pedestal in gen_pit to use ground-relative position instead of map bottom (broken in tall HIGH-zone levels). Add TigerStyle coding guidelines to AGENTS.md adapted for C11. Add tall_test.lvl (40x46) for height zone validation.
This commit is contained in:
@@ -9,7 +9,7 @@ void camera_init(Camera *c, float vp_w, float vp_h) {
|
||||
c->bounds_max = vec2(vp_w, vp_h); /* default: one screen */
|
||||
c->smoothing = 5.0f;
|
||||
c->deadzone = vec2(30.0f, 20.0f);
|
||||
c->look_ahead = vec2(40.0f, 0.0f);
|
||||
c->look_ahead = vec2(40.0f, 30.0f);
|
||||
c->zoom = 1.0f;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,10 @@ void camera_follow(Camera *c, Vec2 target, Vec2 velocity, float dt) {
|
||||
if (velocity.x > 10.0f) desired.x += c->look_ahead.x;
|
||||
else if (velocity.x < -10.0f) desired.x -= c->look_ahead.x;
|
||||
|
||||
/* Vertical look-ahead: lead camera when falling or rising */
|
||||
if (velocity.y > 50.0f) desired.y += c->look_ahead.y;
|
||||
else if (velocity.y < -50.0f) desired.y -= c->look_ahead.y;
|
||||
|
||||
/* Smooth follow using exponential decay */
|
||||
float t = 1.0f - expf(-c->smoothing * dt);
|
||||
c->pos = vec2_lerp(c->pos, desired, t);
|
||||
|
||||
@@ -301,6 +301,137 @@ void particle_emit_jetpack_trail(Vec2 pos, Vec2 dash_dir) {
|
||||
particle_emit(&smoke);
|
||||
}
|
||||
|
||||
void particle_emit_jetpack_boost_burst(Vec2 pos, Vec2 dash_dir) {
|
||||
/* Blue flame accents mixed into the regular jetpack burst */
|
||||
float exhaust_angle = atan2f(-dash_dir.y, -dash_dir.x);
|
||||
|
||||
/* Hot blue core — bright electric blue */
|
||||
ParticleBurst core = {
|
||||
.origin = pos,
|
||||
.count = 10,
|
||||
.speed_min = 90.0f,
|
||||
.speed_max = 220.0f,
|
||||
.life_min = 0.15f,
|
||||
.life_max = 0.35f,
|
||||
.size_min = 2.0f,
|
||||
.size_max = 4.5f,
|
||||
.spread = 0.4f,
|
||||
.direction = exhaust_angle,
|
||||
.drag = 2.5f,
|
||||
.gravity_scale = 0.05f,
|
||||
.color = {80, 160, 255, 255}, /* electric blue */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&core);
|
||||
|
||||
/* Outer blue-white flare */
|
||||
ParticleBurst flare = {
|
||||
.origin = pos,
|
||||
.count = 8,
|
||||
.speed_min = 40.0f,
|
||||
.speed_max = 130.0f,
|
||||
.life_min = 0.2f,
|
||||
.life_max = 0.4f,
|
||||
.size_min = 1.5f,
|
||||
.size_max = 3.0f,
|
||||
.spread = 0.7f,
|
||||
.direction = exhaust_angle,
|
||||
.drag = 3.0f,
|
||||
.gravity_scale = 0.1f,
|
||||
.color = {140, 200, 255, 255}, /* light blue */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&flare);
|
||||
}
|
||||
|
||||
void particle_emit_jetpack_boost_trail(Vec2 pos, Vec2 dash_dir) {
|
||||
/* Continuous blue flame trail while dashing with boost active */
|
||||
float exhaust_angle = atan2f(-dash_dir.y, -dash_dir.x);
|
||||
|
||||
/* Blue flame sparks */
|
||||
ParticleBurst sparks = {
|
||||
.origin = pos,
|
||||
.count = 2,
|
||||
.speed_min = 50.0f,
|
||||
.speed_max = 140.0f,
|
||||
.life_min = 0.1f,
|
||||
.life_max = 0.25f,
|
||||
.size_min = 1.5f,
|
||||
.size_max = 3.0f,
|
||||
.spread = 0.35f,
|
||||
.direction = exhaust_angle,
|
||||
.drag = 3.0f,
|
||||
.gravity_scale = 0.05f,
|
||||
.color = {60, 140, 255, 255}, /* bright blue */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&sparks);
|
||||
|
||||
/* Blue-white wisps */
|
||||
ParticleBurst wisps = {
|
||||
.origin = pos,
|
||||
.count = 1,
|
||||
.speed_min = 20.0f,
|
||||
.speed_max = 50.0f,
|
||||
.life_min = 0.15f,
|
||||
.life_max = 0.35f,
|
||||
.size_min = 2.0f,
|
||||
.size_max = 3.5f,
|
||||
.spread = 0.5f,
|
||||
.direction = exhaust_angle,
|
||||
.drag = 3.5f,
|
||||
.gravity_scale = -0.05f,
|
||||
.color = {160, 210, 255, 200}, /* pale blue */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&wisps);
|
||||
}
|
||||
|
||||
void particle_emit_jetpack_boost_idle(Vec2 pos, bool facing_left) {
|
||||
/* Ambient blue flame simmering from the player's back while boost is
|
||||
* active but the player isn't dashing. Exhaust drifts backward and
|
||||
* slightly downward — a subtle idle glow effect. */
|
||||
float exhaust_angle = facing_left ? 0.0f : (float)M_PI; /* away from facing */
|
||||
|
||||
/* Small blue sparks drifting backward */
|
||||
ParticleBurst sparks = {
|
||||
.origin = pos,
|
||||
.count = 1,
|
||||
.speed_min = 15.0f,
|
||||
.speed_max = 45.0f,
|
||||
.life_min = 0.12f,
|
||||
.life_max = 0.3f,
|
||||
.size_min = 1.0f,
|
||||
.size_max = 2.5f,
|
||||
.spread = 0.8f,
|
||||
.direction = exhaust_angle,
|
||||
.drag = 4.0f,
|
||||
.gravity_scale = 0.15f,
|
||||
.color = {50, 130, 255, 220}, /* medium blue */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&sparks);
|
||||
|
||||
/* Faint blue-white wisps floating up */
|
||||
ParticleBurst wisps = {
|
||||
.origin = pos,
|
||||
.count = 1,
|
||||
.speed_min = 8.0f,
|
||||
.speed_max = 25.0f,
|
||||
.life_min = 0.15f,
|
||||
.life_max = 0.35f,
|
||||
.size_min = 1.5f,
|
||||
.size_max = 2.5f,
|
||||
.spread = 1.0f,
|
||||
.direction = exhaust_angle - 0.3f, /* slightly upward */
|
||||
.drag = 4.5f,
|
||||
.gravity_scale = -0.1f,
|
||||
.color = {140, 200, 255, 160}, /* pale blue, translucent */
|
||||
.color_vary = true,
|
||||
};
|
||||
particle_emit(&wisps);
|
||||
}
|
||||
|
||||
void particle_emit_muzzle_flash(Vec2 pos, Vec2 shoot_dir) {
|
||||
float angle = atan2f(shoot_dir.y, shoot_dir.x);
|
||||
|
||||
|
||||
@@ -73,6 +73,16 @@ void particle_emit_jetpack_burst(Vec2 pos, Vec2 dash_dir);
|
||||
/* Jetpack exhaust trail (call each frame while dashing) */
|
||||
void particle_emit_jetpack_trail(Vec2 pos, Vec2 dash_dir);
|
||||
|
||||
/* Blue flame burst (mixed into jetpack burst when boost is active) */
|
||||
void particle_emit_jetpack_boost_burst(Vec2 pos, Vec2 dash_dir);
|
||||
|
||||
/* Continuous blue flame trail during jetpack boost (call each frame while dashing + boosted) */
|
||||
void particle_emit_jetpack_boost_trail(Vec2 pos, Vec2 dash_dir);
|
||||
|
||||
/* Ambient blue glow from jetpack while boost is active but not dashing
|
||||
* (call each frame; facing_left determines exhaust side) */
|
||||
void particle_emit_jetpack_boost_idle(Vec2 pos, bool facing_left);
|
||||
|
||||
/* Muzzle flash (short bright burst in shoot direction) */
|
||||
void particle_emit_muzzle_flash(Vec2 pos, Vec2 shoot_dir);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -288,6 +288,11 @@ void player_update(Entity *self, float dt, const Tilemap *map) {
|
||||
);
|
||||
particle_emit_jetpack_trail(exhaust_pos, pd->dash_dir);
|
||||
|
||||
/* Blue flame trail when boost is active */
|
||||
if (pd->jetpack_boost_timer > 0) {
|
||||
particle_emit_jetpack_boost_trail(exhaust_pos, pd->dash_dir);
|
||||
}
|
||||
|
||||
/* Skip normal movement during dash */
|
||||
physics_update(body, dt, map);
|
||||
animation_update(&self->anim, dt);
|
||||
@@ -330,10 +335,28 @@ void player_update(Entity *self, float dt, const Tilemap *map) {
|
||||
);
|
||||
particle_emit_jetpack_burst(exhaust_pos, pd->dash_dir);
|
||||
|
||||
/* Blue flame accents when boost powerup is active */
|
||||
if (pd->jetpack_boost_timer > 0) {
|
||||
particle_emit_jetpack_boost_burst(exhaust_pos, pd->dash_dir);
|
||||
}
|
||||
|
||||
audio_play_sound(s_sfx_dash, 96);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ── Jetpack boost idle glow ─────────────── */
|
||||
/* Ambient blue flame from the player's back while boost is active
|
||||
* and not dashing. Emits from the rear center of the sprite. */
|
||||
if (pd->jetpack_boost_timer > 0) {
|
||||
bool facing_left = (self->flags & ENTITY_FACING_LEFT) != 0;
|
||||
Vec2 back_pos = vec2(
|
||||
facing_left ? body->pos.x + body->size.x - 1.0f
|
||||
: body->pos.x + 1.0f,
|
||||
body->pos.y + body->size.y * 0.45f
|
||||
);
|
||||
particle_emit_jetpack_boost_idle(back_pos, facing_left);
|
||||
}
|
||||
|
||||
/* ── Horizontal movement ─────────────────── */
|
||||
float target_vx = 0.0f;
|
||||
if (hold_left) target_vx -= PLAYER_SPEED;
|
||||
|
||||
Reference in New Issue
Block a user