lyra-engine/examples/testbed/src/free_fly_camera.rs

106 lines
3.5 KiB
Rust

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<DeltaTime>, handler: Res<ActionHandler>, 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, &[]);
}
}