use bevy_ecs::prelude::*;
use glam::Vec3;
#[derive(Component)]
pub struct CameraEffects {
pub fov_offset: f32,
pub fov_target: f32,
pub fov_speed: f32,
pub shake_intensity: f32,
pub shake_decay: f32,
pub shake_frequency: f32,
shake_timer: f32,
pub head_bob_enabled: bool,
pub head_bob_amplitude: f32,
pub head_bob_frequency: f32,
pub head_bob_timer: f32,
}
impl Default for CameraEffects {
fn default() -> Self {
Self {
fov_offset: 0.0,
fov_target: 0.0,
fov_speed: 5.0,
shake_intensity: 0.0,
shake_decay: 5.0,
shake_frequency: 15.0,
shake_timer: 0.0,
head_bob_enabled: false,
head_bob_amplitude: 0.05,
head_bob_frequency: 8.0,
head_bob_timer: 0.0,
}
}
}
impl CameraEffects {
pub fn add_shake(&mut self, intensity: f32) {
self.shake_intensity = self.shake_intensity.max(intensity);
}
pub fn tick(&mut self, dt: f32, is_walking: bool) -> (Vec3, f32) {
let mut pos_offset = Vec3::ZERO;
if self.shake_intensity > 0.001 {
self.shake_timer += dt;
let t = self.shake_timer * self.shake_frequency * std::f32::consts::TAU;
let sx = t.sin() * self.shake_intensity * 0.5;
let sy = (t * 1.3).cos() * self.shake_intensity;
pos_offset += Vec3::new(sx, sy, 0.0);
self.shake_intensity = (self.shake_intensity - self.shake_decay * dt).max(0.0);
} else {
self.shake_intensity = 0.0;
self.shake_timer = 0.0;
}
if self.head_bob_enabled && is_walking {
self.head_bob_timer += dt * self.head_bob_frequency;
let bob_y = (self.head_bob_timer * std::f32::consts::TAU).sin()
* self.head_bob_amplitude;
let bob_x = (self.head_bob_timer * std::f32::consts::PI).cos()
* self.head_bob_amplitude * 0.5;
pos_offset += Vec3::new(bob_x, bob_y, 0.0);
} else {
self.head_bob_timer *= 0.9_f32.powf(dt * 60.0);
}
self.fov_offset += (self.fov_target - self.fov_offset) * (self.fov_speed * dt).min(1.0);
(pos_offset, self.fov_offset)
}
}