use lyra_engine::{ game::Game, input::{ActionHandler, CommonActionLabel}, math::{Quat, Vec3, EulerRot}, plugin::Plugin, ecs::{Component, query::{Res, View}}, DeltaTime, scene::CameraComponent, }; /* enum FreeFlyCameraActions { MoveForwardBackward, MoveLeftRight, MoveUpDown, LookLeftRight, LookUpDown, LookRoll, } */ #[derive(Clone, Component)] pub struct FreeFlyCamera { pub speed: f32, pub slow_speed_factor: f32, pub look_speed: f32, pub mouse_sensitivity: f32, pub look_with_keys: bool, } impl Default for FreeFlyCamera { fn default() -> Self { Self { speed: 4.0, slow_speed_factor: 0.25, look_speed: 0.3, mouse_sensitivity: 1.0, look_with_keys: false, } } } impl FreeFlyCamera { #[allow(dead_code)] pub fn new(speed: f32, slow_speed_factor: f32, look_speed: f32, mouse_sensitivity: f32, look_with_keys: bool) -> Self { Self { speed, slow_speed_factor, look_speed, mouse_sensitivity, look_with_keys, } } } pub fn free_fly_camera_controller(delta_time: Res, handler: Res, view: View<(&mut CameraComponent, &FreeFlyCamera)>) -> anyhow::Result<()> { let delta_time = **delta_time; for (mut cam, fly) in view.into_iter() { let forward = cam.transform.forward(); let left = cam.transform.left(); let up = Vec3::Y; let move_y = handler.get_axis_modifier(CommonActionLabel::MoveUpDown).unwrap_or(0.0); let move_x = handler.get_axis_modifier(CommonActionLabel::MoveLeftRight).unwrap_or(0.0); let move_z = handler.get_axis_modifier(CommonActionLabel::MoveForwardBackward).unwrap_or(0.0); let mut velocity = Vec3::ZERO; velocity += move_y * up; velocity += move_x * left; velocity += move_z * forward; if velocity != Vec3::ZERO { cam.transform.translation += velocity.normalize() * fly.speed * delta_time; // TODO: speeding up } let motion_x = handler.get_axis_modifier(CommonActionLabel::LookLeftRight).unwrap_or(0.0); let motion_y = handler.get_axis_modifier(CommonActionLabel::LookUpDown).unwrap_or(0.0); let motion_z = handler.get_axis_modifier(CommonActionLabel::LookRoll).unwrap_or(0.0); let mut camera_rot = Vec3::ZERO; camera_rot.y -= motion_x * fly.mouse_sensitivity; camera_rot.x -= motion_y * fly.mouse_sensitivity; camera_rot.z -= motion_z * fly.mouse_sensitivity; if camera_rot != Vec3::ZERO { let look_velocity = camera_rot * fly.look_speed * delta_time; let (mut y, mut x, _) = cam.transform.rotation.to_euler(EulerRot::YXZ); x += look_velocity.x; y += look_velocity.y; x = x.clamp(-1.54, 1.54); // rotation is not commutative, keep this order to avoid unintended roll cam.transform.rotation = Quat::from_axis_angle(Vec3::Y, y) * Quat::from_axis_angle(Vec3::X, x); } } Ok(()) } /// A plugin that adds the free fly camera controller system to the world. It is expected that /// there is a [`FreeFlyCamera`] in the world, if there isn't, the camera would not move. pub struct FreeFlyCameraPlugin; impl Plugin for FreeFlyCameraPlugin { fn setup(&self, game: &mut Game) { game.with_system("free_fly_camera_system", free_fly_camera_controller, &[]); } }