use std::time::Duration;
use super::{post_process, LOGICAL_HEIGHT, LOGICAL_WIDTH};
use bevy::prelude::*;
use bevy_smooth_pixel_camera::components::PixelCamera;
use bevy_smooth_pixel_camera::viewport::ViewportSize;
pub struct CameraPlugin;
impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
post_process::ChromaticAberrationPlugin,
))
.init_resource::<CameraRig>()
.add_systems(Startup, setup_camera)
.add_systems(FixedUpdate, update_camera);
}
}
#[derive(Resource)]
pub struct CameraRig {
pub targetting: usize,
precision: f32,
pub snap_duration: Duration,
}
impl CameraRig {
pub fn lag(&self) -> f32 {
self.precision
}
pub fn set_lag(&mut self, lag: f32) {
self.precision = lag.clamp(0.0, 0.99);
}
}
impl Default for CameraRig {
fn default() -> Self {
Self {
targetting: 0,
precision: 0.7,
snap_duration: Duration::from_secs_f32(10f32.recip()),
}
}
}
#[derive(Component, Default)]
pub struct CameraTarget(pub usize);
#[derive(Component, Default)]
struct Camera;
#[derive(Bundle)]
struct CameraBundle {
camera: Camera,
camera_2d: Camera2dBundle,
pixel_camera: PixelCamera,
chroma_aberration: post_process::ChromaticAberattionSettings,
}
fn setup_camera(mut commands: Commands) {
commands.spawn(CameraBundle {
camera: Camera,
camera_2d: Camera2dBundle::default(),
pixel_camera: PixelCamera::from_size(ViewportSize::AutoMin {
min_width: LOGICAL_WIDTH,
min_height: LOGICAL_HEIGHT,
}),
chroma_aberration: post_process::ChromaticAberattionSettings {
..default()
},
});
}
fn update_camera(
mut camera: Query<(&mut PixelCamera, &GlobalTransform), With<Camera>>,
targets: Query<(&GlobalTransform, &CameraTarget)>,
rig: Res<CameraRig>,
time: Res<Time>,
) {
let (mut camera, cam_transform) = camera.single_mut();
let targeted = targets
.iter()
.filter(|(_, t)| t.0 == rig.targetting)
.collect::<Vec<_>>();
let goal = targeted
.iter()
.map(|(transform, _)| transform.translation())
.reduce(|total, e| total + e)
.map(|total| total / targeted.len() as f32);
if let Some(goal) = goal {
let source = cam_transform.translation();
let lambda = -rig.snap_duration.as_secs_f32() / rig.precision.log2();
let alpha = 2.0f32.powf(-time.delta_seconds() / lambda);
let lerped = source * alpha + goal * (1.0 - alpha);
camera.subpixel_pos = lerped.xy();
}
}