use bevy::prelude::*; use leafwing_input_manager::prelude::*; /// Marks the root entity in a camera rig hierarchy. #[derive(Component, Debug, Reflect)] pub struct CameraRig { pub camera_entity: Entity, pub joint_entity: Entity, pub target: Option, } /// Parent of the camera entity, allowing camera zoom and rotation. #[derive(Component, Debug, Default, Reflect)] pub struct CameraJoint; /// Marks an entity as the primary camera. #[derive(Component, Debug, Default, Reflect)] pub struct PrimaryCamera; /// Spawns a camera rig hierarchy /// /// ``` /// +-- CameraRig (translation and rotation) /// | +-- CameraJoint (zoom) /// | | +-- PrimaryCamera /// ``` pub fn spawn_camera_rig(mut commands: Commands) { let mut camera_entity: Entity = Entity::PLACEHOLDER; let mut joint_entity: Entity = Entity::PLACEHOLDER; commands .spawn(( InputManagerBundle::with_map( InputMap::new([ (CameraAction::Move, UserInput::from(VirtualDPad::wasd())), ( CameraAction::Zoom, UserInput::from(VirtualAxis::vertical_arrow_keys().inverted()), ), ( CameraAction::ZoomQuantized, UserInput::from(VirtualAxis { positive: InputKind::MouseWheel(MouseWheelDirection::Up), negative: InputKind::MouseWheel(MouseWheelDirection::Down), }), ), ]) ), SpatialBundle::default(), )) .with_children(|rig| { joint_entity = rig .spawn(( CameraJoint, SpatialBundle::from_transform(Transform::from_xyz(0.0, 0.0, 10.0)), )) .with_children(|joint| { camera_entity = joint .spawn(( PrimaryCamera, Camera3dBundle { // projection: Projection::Perspective(PerspectiveProjection { // fov: (50.5_f32).to_radians(), // ..default() // }), ..default() }, )) .id(); }) .id(); }) .insert(CameraRig { camera_entity, joint_entity, target: None, }); } #[derive(Actionlike, PartialEq, Eq, Hash, Clone, Copy, Debug, Reflect)] pub enum CameraAction { Move, Zoom, ZoomQuantized, } impl CameraAction { pub const ZOOM_SPEED: f32 = 20.0; pub const ZOOM_MIN: f32 = 1.0; pub const ZOOM_MAX: f32 = 100.0; pub const ZOOM_LEN: f32 = Self::ZOOM_MAX - Self::ZOOM_MIN; pub fn clamp_zoom(z: f32) -> f32 { z.clamp(Self::ZOOM_MIN, Self::ZOOM_MAX) } pub fn current_zoom(z: f32) -> f32 { (z - Self::ZOOM_MIN) / Self::ZOOM_LEN } } pub type CameraActionState = ActionState; pub fn control_camera_rig( mut query_rig: Query<(&CameraActionState, &CameraRig, &mut Transform)>, mut query_joint: Query<&mut Transform, (With, Without)>, time: Res