Initial commit

This commit is contained in:
Thomas
2026-02-28 18:00:58 +00:00
commit c66c12ae68
587 changed files with 239570 additions and 0 deletions

90
src/engine/camera.c Normal file
View File

@@ -0,0 +1,90 @@
#include "engine/camera.h"
#include <stdlib.h>
#include <math.h>
void camera_init(Camera *c, float vp_w, float vp_h) {
c->pos = vec2_zero();
c->viewport = vec2(vp_w, vp_h);
c->bounds_min = vec2_zero();
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);
}
void camera_set_bounds(Camera *c, float world_w, float world_h) {
c->bounds_min = vec2_zero();
c->bounds_max = vec2(world_w, world_h);
}
void camera_follow(Camera *c, Vec2 target, Vec2 velocity, float dt) {
/* Target is the center point we want to follow */
Vec2 desired;
desired.x = target.x - c->viewport.x * 0.5f;
desired.y = target.y - c->viewport.y * 0.5f;
/* Look-ahead: shift camera in the direction of movement */
if (velocity.x > 10.0f) desired.x += c->look_ahead.x;
else if (velocity.x < -10.0f) desired.x -= c->look_ahead.x;
/* Smooth follow using exponential decay */
float t = 1.0f - expf(-c->smoothing * dt);
c->pos = vec2_lerp(c->pos, desired, t);
/* Clamp to world bounds */
c->pos.x = clampf(c->pos.x, c->bounds_min.x,
c->bounds_max.x - c->viewport.x);
c->pos.y = clampf(c->pos.y, c->bounds_min.y,
c->bounds_max.y - c->viewport.y);
}
Vec2 camera_world_to_screen(const Camera *c, Vec2 world_pos) {
Vec2 screen = vec2_sub(world_pos, c->pos);
/* Apply shake offset */
screen.x += c->shake_offset.x;
screen.y += c->shake_offset.y;
return screen;
}
Vec2 camera_screen_to_world(const Camera *c, Vec2 screen_pos) {
return vec2_add(screen_pos, c->pos);
}
/* ── Screen shake ────────────────────────────────── */
static float randf_sym(void) {
/* Random float in [-1, 1] */
return ((float)rand() / (float)RAND_MAX) * 2.0f - 1.0f;
}
void camera_shake(Camera *c, float intensity, float duration) {
/* Take the stronger shake if one is already active */
if (intensity > c->shake_intensity || c->shake_timer <= 0) {
c->shake_intensity = intensity;
c->shake_timer = duration;
}
}
void camera_update_shake(Camera *c, float dt) {
if (c->shake_timer <= 0) {
c->shake_offset = vec2_zero();
return;
}
c->shake_timer -= dt;
/* Decay intensity as shake expires */
float t = c->shake_timer > 0 ? c->shake_timer / 0.3f : 0; /* ~0.3s reference */
if (t > 1.0f) t = 1.0f;
float current = c->shake_intensity * t;
/* Random offset, rounded to whole pixels for crisp pixel art */
c->shake_offset.x = roundf(randf_sym() * current);
c->shake_offset.y = roundf(randf_sym() * current);
if (c->shake_timer <= 0) {
c->shake_timer = 0;
c->shake_intensity = 0;
c->shake_offset = vec2_zero();
}
}