diff --git a/apps/game/src/camera.rs b/apps/game/src/camera.rs index 835d217..23845d2 100644 --- a/apps/game/src/camera.rs +++ b/apps/game/src/camera.rs @@ -7,6 +7,53 @@ use crate::ui::util::cursor_over_ui; #[derive(Component)] pub struct MainCamera; +/// Camera mode determines how the camera behaves. +/// - Orbit: Free-look inspection around a target (Galaxy view, docked inspection) +/// - Follow: Tracks behind a moving entity (player ship during flight) +/// - Cinematic: Fixed cinematic shot (docked view, cutscenes) +#[derive(Debug, Clone, Copy, PartialEq, Default)] +pub enum CameraMode { + #[default] + Orbit, + Follow, + Cinematic, +} + +impl CameraMode { + pub fn is_orbit(&self) -> bool { + matches!(self, Self::Orbit) + } + + pub fn is_follow(&self) -> bool { + matches!(self, Self::Follow) + } + + pub fn is_cinematic(&self) -> bool { + matches!(self, Self::Cinematic) + } +} + +/// Global camera state resource. Controls which camera mode is active +/// and which entity the camera should follow (if any). +#[derive(Resource, Default, Debug)] +pub struct CameraState { + pub mode: CameraMode, + pub target_entity: Option, + pub follow_distance: f32, + pub follow_height: f32, +} + +/// Follow camera component. Attached to the MainCamera when in Follow mode, +/// this configures how the camera tracks its target. +#[derive(Component, Debug, Clone)] +pub struct FollowCamera { + pub target: Entity, + pub distance: f32, + pub height: f32, + pub stiffness: f32, + pub damping: f32, +} + /// Orbit-style camera: rotates around `target` at `distance`, controlled by mouse. /// Used for inspection scenes like Galaxy where there is no player to follow. /// @@ -73,7 +120,10 @@ const ORBIT_MAX_DISTANCE: f32 = 1500.0; /// /// Drag is suppressed when the cursor is over any UI node — otherwise clicking /// buttons or panels would also rotate the camera. +/// +/// Only runs when camera mode is Orbit. pub fn orbit_camera_control( + camera_state: Res, mouse_input: Res>, primary_window: Query<&Window, With>, mut mouse_motion: EventReader, @@ -81,6 +131,12 @@ pub fn orbit_camera_control( mut query: Query<(&mut Transform, &mut OrbitCamera), With>, ui_nodes: Query<(&bevy::ui::ComputedNode, &GlobalTransform)>, ) { + // Only run orbit controls in Orbit mode + if camera_state.mode != CameraMode::Orbit { + mouse_motion.clear(); + scroll_events.clear(); + return; + } let Ok((mut transform, mut orbit)) = query.single_mut() else { // Drain pending input to avoid stale buildup when there's no camera. mouse_motion.clear(); @@ -162,3 +218,102 @@ pub fn apply_orbit_reset( orbit.reset(); commands.remove_resource::(); } + +/// Follow camera system. Tracks behind the target entity (player ship) during flight. +/// The camera maintains a fixed distance and height behind the target, smoothly +/// interpolating to the ideal position each frame. +pub fn follow_camera_system( + time: Res