diff --git a/src/camera.rs b/src/camera.rs index 9305bfa..0667d90 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,58 +1,122 @@ -use bevy::prelude::*; - -use crate::{ - geometry::{CyberBikeModel, SPAWN_ALTITUDE}, - input::InputState, +use bevy::{ + prelude::*, + render::camera::{ActiveCameras, Camera, CameraPlugin}, }; -pub(crate) const CAM_DIST: f32 = 15.0; +use crate::{geometry::CyberBikeModel, input::InputState}; // 85 degrees in radians const MAX_PITCH: f32 = 1.48353; -#[derive(Component, Debug)] -pub struct CyberCam; +#[derive(Clone, Copy, Eq, PartialEq, Debug, Hash, Component)] +enum CyberCameras { + Hero, + Debug, +} -fn setup_cybercam(mut commands: Commands) { - let projection = PerspectiveProjection { +impl CyberCameras { + fn next(self) -> Self { + match self { + CyberCameras::Debug => CyberCameras::Hero, + CyberCameras::Hero => CyberCameras::Debug, + } + } +} + +fn setup_cybercams(mut commands: Commands) { + let hero_projection = PerspectiveProjection { fov: std::f32::consts::FRAC_PI_3, ..Default::default() }; commands .spawn_bundle(PerspectiveCameraBundle { - transform: Transform::from_xyz(SPAWN_ALTITUDE + CAM_DIST, 0.0, 0.0) - .looking_at(Vec3::ZERO, Vec3::Y), - perspective_projection: projection, + perspective_projection: hero_projection, ..Default::default() }) - .insert(CyberCam); + .insert(CyberCameras::Hero); + + commands + .spawn_bundle(PerspectiveCameraBundle::with_name("Inactive")) + .insert(CyberCameras::Debug); } fn follow_cyberbike( - bike_query: Query<&Transform, (Without, With)>, - mut cam_query: Query<&mut Transform, (With, Without)>, + mut query: QuerySet<( + // 0: the bike + QueryState<&Transform, With>, + // 1: the cameras + QueryState<(&mut Transform, &CyberCameras)>, + )>, input: Res, ) { - let bike_xform = bike_query.single(); + let bike_xform = *query.q0().single(); let up = bike_xform.translation.normalize(); - let look_at = bike_xform.translation + (bike_xform.forward() * 200.0); - let cam_pos = bike_xform.translation + (bike_xform.back() * 2.7) + (up * 2.4); + for (mut cam_xform, cam_type) in query.q1().iter_mut() { + match *cam_type { + CyberCameras::Hero => { + let look_at = bike_xform.translation + (bike_xform.forward() * 200.0); + let cam_pos = bike_xform.translation + (bike_xform.back() * 2.7) + (up * 2.4); - let mut cam_xform = cam_query.single_mut(); - cam_xform.translation = cam_pos; - cam_xform.look_at(look_at, up); + cam_xform.translation = cam_pos; + cam_xform.look_at(look_at, up); - // handle input pitch - let angle = input.pitch.powi(3) * MAX_PITCH; - let axis = cam_xform.right(); - cam_xform.rotate(Quat::from_axis_angle(axis, angle)); + // handle input pitch + let angle = input.pitch.powi(3) * MAX_PITCH; + let axis = cam_xform.right(); + cam_xform.rotate(Quat::from_axis_angle(axis, angle)); + } + CyberCameras::Debug => { + let pos = bike_xform.translation + + (bike_xform.forward() * 10.0) + + (bike_xform.left() * 30.0) + + (bike_xform.up() * 7.0); + cam_xform.translation = pos; + cam_xform.look_at(bike_xform.translation, up); + } + } + } +} + +fn update_active_camera( + mut active_cams: ResMut, + state: Res>, + mut query: Query<(&mut Camera, &CyberCameras)>, +) { + active_cams.remove(CameraPlugin::CAMERA_3D); + + // set all cameras to inactive + for (mut cam, _) in query.iter_mut() { + cam.name = Some("Inactive".to_string()); + } + + // find the camera with the current state, set its name to be active + for (mut cam, _) in query + .iter_mut() + .filter(|(_, cybercam)| state.current().eq(cybercam)) + { + cam.name = Some(CameraPlugin::CAMERA_3D.to_string()); + } + + active_cams.add(CameraPlugin::CAMERA_3D); +} + +fn cycle_cam_state(mut state: ResMut>, mut keys: ResMut>) { + if keys.just_pressed(KeyCode::D) { + let new_state = state.current().next(); + info!("{:?}", new_state); + state.set(new_state).unwrap(); + keys.reset(KeyCode::D); + } } pub struct CyberCamPlugin; impl Plugin for CyberCamPlugin { fn build(&self, app: &mut bevy::prelude::App) { - app.add_startup_system(setup_cybercam) + app.add_startup_system(setup_cybercams) + .add_state(CyberCameras::Hero) + .add_system(cycle_cam_state) + .add_system(update_active_camera) .add_system(follow_cyberbike); } }