diff --git a/src/camera.rs b/src/camera.rs index 1dbf722..15a1c51 100644 --- a/src/camera.rs +++ b/src/camera.rs @@ -1,7 +1,7 @@ use avian3d::prelude::*; use bevy::prelude::*; -use crate::physics_layers::GameLayer; +use crate::{controls::Controls, physics_layers::GameLayer, player::PlayerMovement}; #[derive(Component, Reflect, Debug)] pub struct CameraTarget; @@ -9,38 +9,59 @@ pub struct CameraTarget; #[derive(Component, Reflect, Debug)] pub struct CameraArmRotation; +#[derive(Component, Reflect, Debug)] +#[reflect(Component)] +pub struct CameraRotation(pub f32); + +#[derive(Resource, Reflect, Debug, Default)] +#[reflect(Resource)] +pub struct CameraState { + pub cutscene: bool, +} + #[derive(Component, Reflect, Debug)] pub struct MainCamera { - arm: Vec3, + dir: Dir3, + distance: f32, } impl MainCamera { fn new(arm: Vec3) -> Self { - Self { arm } + let (dir, distance) = Dir3::new_and_length(arm).expect("invalid arm length"); + Self { dir, distance } } } pub fn plugin(app: &mut App) { + app.register_type::(); + app.register_type::(); + app.init_resource::(); app.add_systems(Startup, startup); - app.add_systems(Update, update); + app.add_systems(Update, (update, rotate_view)); } fn startup(mut commands: Commands) { commands.spawn(( Camera3d::default(), MainCamera::new(Vec3::new(0., 1., -12.)), + CameraRotation(0.), )); } fn update( mut cam: Query< - (&MainCamera, &mut Transform), + (&MainCamera, &mut Transform, &CameraRotation), (Without, Without), >, target: Query<&GlobalTransform, (With, Without)>, arm_rotation: Query<&Transform, With>, spatial_query: SpatialQuery, + cam_state: Res, ) { + if cam_state.cutscene { + return; + } + let Ok(target) = target.get_single().map(|t| t.translation()) else { return; }; @@ -49,20 +70,13 @@ fn update( return; }; - let Ok((camera, mut cam_transform)) = cam.get_single_mut() else { + let Ok((camera, mut cam_transform, cam_rotation)) = cam.get_single_mut() else { return; }; - let target_transform = Transform::from_translation(target) - * Transform::from_rotation(rotation.rotation) - * Transform::from_translation(camera.arm); + let direction = rotation.rotation * Quat::from_rotation_y(cam_rotation.0) * camera.dir; - let ideal_cam_pos = target_transform.translation; - - let max_distance = camera.arm.length(); - let Ok(direction) = Dir3::new(ideal_cam_pos - target) else { - return; - }; + let max_distance = camera.distance; let filter = SpatialQueryFilter::from_mask(LayerMask(GameLayer::Level.to_bits())); let cam_pos = if let Some(first_hit) = @@ -70,8 +84,29 @@ fn update( { target + (direction * first_hit.distance) } else { - ideal_cam_pos + target + (direction * camera.distance) }; *cam_transform = Transform::from_translation(cam_pos).looking_at(target, Vec3::Y); } + +fn rotate_view( + mut controls: ResMut, + mut cam: Query<&mut CameraRotation>, + movement: Res, +) { + let Ok(mut cam) = cam.get_single_mut() else { + return; + }; + + if !controls.keyboard_state.view_mode { + if movement.any_direction { + cam.0 = 0.; + } + return; + } + + cam.0 += controls.keyboard_state.look_dir.x * -0.001; + + controls.keyboard_state.look_dir = Vec2::ZERO; +} diff --git a/src/controls.rs b/src/controls.rs index 701c209..7d676ec 100644 --- a/src/controls.rs +++ b/src/controls.rs @@ -14,6 +14,7 @@ pub struct ControlState { pub move_dir: Vec2, pub look_dir: Vec2, pub jump: bool, + pub view_mode: bool, } #[derive(Resource, Debug, Default)] @@ -76,6 +77,7 @@ fn gamepad_controls( move_dir: gamepad.left_stick(), look_dir, jump: gamepad.pressed(GamepadButton::South), + view_mode: gamepad.pressed(GamepadButton::East), }; if gamepad.just_pressed(GamepadButton::North) { @@ -120,6 +122,7 @@ fn keyboard_controls(keyboard: Res>, mut controls: ResMut, mut commands: Commands) { diff --git a/src/cutscene.rs b/src/cutscene.rs index 7d26683..08f965a 100644 --- a/src/cutscene.rs +++ b/src/cutscene.rs @@ -1,5 +1,5 @@ use crate::{ - DebugVisuals, + camera::CameraState, tb_entities::{CameraTarget, CutsceneCamera, CutsceneCameraMovementEnd}, }; use bevy::prelude::*; @@ -27,7 +27,7 @@ pub fn plugin(app: &mut App) { fn on_start_cutscene( trigger: Trigger, - mut res: ResMut, + mut cam_state: ResMut, mut cutscene_state: ResMut, cutscenes: Query<(&Transform, &CutsceneCamera, &Target), Without>, cutscene_movement: Query<(&Transform, &CutsceneCameraMovementEnd, &Target), Without>, @@ -35,7 +35,7 @@ fn on_start_cutscene( ) { let cutscene = trigger.event().0.clone(); - res.cam_follow = false; + cam_state.cutscene = true; // asumes `name` and `targetname` are equal let Some((t, _, target)) = cutscenes @@ -65,7 +65,7 @@ fn on_start_cutscene( } fn update( - mut res: ResMut, + mut cam_state: ResMut, mut cutscene_state: ResMut, mut cam: Query<&mut Transform, With>, time: Res