From 249b87afed0b6027bbaa0e95eeb190e95c6d0a1c Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Tue, 24 Oct 2023 20:03:27 -0400 Subject: [PATCH] Create simple keyboard controlled free fly camera --- examples/testbed/Cargo.lock | 1 + examples/testbed/Cargo.toml | 3 +- examples/testbed/src/free_fly_camera.rs | 122 ++++++++++++++++++++++++ examples/testbed/src/main.rs | 13 ++- src/input.rs | 1 + src/math/transform.rs | 12 ++- src/render/camera.rs | 8 +- 7 files changed, 149 insertions(+), 11 deletions(-) create mode 100644 examples/testbed/src/free_fly_camera.rs diff --git a/examples/testbed/Cargo.lock b/examples/testbed/Cargo.lock index f7dfad3..541a4a9 100644 --- a/examples/testbed/Cargo.lock +++ b/examples/testbed/Cargo.lock @@ -2313,6 +2313,7 @@ version = "0.1.0" dependencies = [ "anyhow", "async-std", + "edict", "fps_counter", "lyra-engine", "tracing", diff --git a/examples/testbed/Cargo.toml b/examples/testbed/Cargo.toml index 25efcb5..699c48d 100644 --- a/examples/testbed/Cargo.toml +++ b/examples/testbed/Cargo.toml @@ -11,5 +11,6 @@ anyhow = "1.0.75" async-std = "1.12.0" tracing = "0.1.37" fps_counter = "2.0.0" +edict = "0.5.0" -[workspace] \ No newline at end of file +[workspace] diff --git a/examples/testbed/src/free_fly_camera.rs b/examples/testbed/src/free_fly_camera.rs new file mode 100644 index 0000000..846f527 --- /dev/null +++ b/examples/testbed/src/free_fly_camera.rs @@ -0,0 +1,122 @@ +use std::ops::Deref; + +use edict::{World, Component}; +use lyra_engine::{math::{Vec3, Angle, Quat}, input::{InputButtons, KeyCode, MouseMotion}, ecs::{SimpleSystem, components::camera::CameraComponent, EventQueue}, game::Game, plugin::Plugin}; +use tracing::debug; + +#[derive(Clone, Component)] +pub struct FreeFlyCamera { + pub speed: f32, + pub look_speed: f32, + pub look_with_keys: bool +} + +impl Default for FreeFlyCamera { + fn default() -> Self { + Self { + speed: 0.07, + look_speed: 0.01, + look_with_keys: false + } + } +} + +impl FreeFlyCamera { + pub fn new(speed: f32, look_speed: f32, look_with_keys: bool) -> Self { + Self { + speed, + look_speed, + look_with_keys + } + } +} + +pub struct FreeFlyCameraController; + +impl SimpleSystem for FreeFlyCameraController { + fn execute_mut(&mut self, world: &mut World) -> anyhow::Result<()> { + let mut camera_rot = Vec3::default(); + + let keys = world.get_resource::>() + .map(|r| r.deref().clone()); + if keys.is_none() { + return Ok(()); + } + let keys = keys.unwrap(); + + if keys.is_pressed(KeyCode::Left) { + camera_rot.y += 1.0; + } + + if keys.is_pressed(KeyCode::Right) { + camera_rot.y -= 1.0; + } + + if keys.is_pressed(KeyCode::Up) { + camera_rot.x += 1.0; + } + + if keys.is_pressed(KeyCode::Down) { + camera_rot.x -= 1.0; + } + + if keys.is_pressed(KeyCode::E) { + camera_rot.z -= 1.0; + } + + if keys.is_pressed(KeyCode::Q) { + camera_rot.z += 1.0; + } + + let camera_rot = camera_rot.normalize(); + + for (cam, fly) in world.query_mut::<(&mut CameraComponent, &mut FreeFlyCamera)>().iter_mut() { + let forward = cam.transform.forward(); + let left = cam.transform.left(); + let up = cam.transform.up(); + + let mut velocity = Vec3::ZERO; + + if keys.is_pressed(KeyCode::A) { + velocity -= left; + } + + if keys.is_pressed(KeyCode::D) { + velocity += left; + } + + if keys.is_pressed(KeyCode::W) { + velocity += forward; + } + + if keys.is_pressed(KeyCode::S) { + velocity -= forward; + } + + if keys.is_pressed(KeyCode::C) { + velocity += up; + } + + if keys.is_pressed(KeyCode::Z) { + velocity -= up; + } + + if velocity != Vec3::ZERO { + cam.transform.translation += velocity.normalize() * fly.speed; + } + + if !camera_rot.is_nan() { + let look_velocity = camera_rot.normalize() * fly.look_speed; + cam.transform.rotation *= Quat::from_rotation_x(look_velocity.x) * Quat::from_rotation_y(look_velocity.y) * Quat::from_rotation_z(look_velocity.z); + } + } + + Ok(()) + } +} + +impl Plugin for FreeFlyCameraController { + fn setup(&self, game: &mut Game) { + game.with_system("free_fly_camera_controller", FreeFlyCameraController, &[]); + } +} \ No newline at end of file diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index 14b79fd..38bfec0 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -1,9 +1,11 @@ -use lyra_engine::{math, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent}, EventQueue}, math::Transform, input::{KeyCode, InputButtons, MouseMotion}, game::Game}; - +use lyra_engine::{math::{self, Vec3}, ecs::{World, components::{transform::TransformComponent, camera::CameraComponent, model::ModelComponent}, EventQueue, SimpleSystem, Component}, math::Transform, input::{KeyCode, InputButtons, MouseMotion}, game::Game, plugin::Plugin, render::window::{CursorGrabMode, WindowOptions}, change_tracker::Ct}; use lyra_engine::assets::{ResourceManager, Model}; use tracing::debug; +mod free_fly_camera; +use free_fly_camera::{FreeFlyCameraController, FreeFlyCamera}; + /* pub const VERTICES: &[Vertex] = &[ Vertex { position: [-0.0868241, 0.49240386, 0.0], tex_coords: [0.4131759, 0.00759614], }, // A Vertex { position: [-0.49513406, 0.06958647, 0.0], tex_coords: [0.0048659444, 0.43041354], }, // B @@ -46,8 +48,8 @@ async fn main() { let mut camera = CameraComponent::new_3d(); camera.transform.translation += math::Vec3::new(0.0, 0.0, 7.5); //camera.transform.rotate_y(Angle::Degrees(-25.0)); - camera.transform.rotate_z(math::Angle::Degrees(-90.0)); - world.spawn((camera,)); + //camera.transform.rotate_z(math::Angle::Degrees(-90.0)); + world.spawn(( camera, FreeFlyCamera::default() )); Ok(()) }; @@ -156,7 +158,7 @@ async fn main() { }; let jiggle_plugin = move |game: &mut Game| { - game.with_system("jiggle", jiggle_system, &["input"]); + //game.with_system("jiggle", jiggle_system, &["input"]); }; Game::initialize().await @@ -164,5 +166,6 @@ async fn main() { .with_startup_system(setup_sys) //.with_plugin(fps_plugin) .with_plugin(jiggle_plugin) + .with_plugin(FreeFlyCameraController) .run().await; } diff --git a/src/input.rs b/src/input.rs index c377f37..b17a729 100755 --- a/src/input.rs +++ b/src/input.rs @@ -139,6 +139,7 @@ pub struct CursorEnteredWindow; #[derive(Clone, Debug, Eq, PartialEq)] pub struct CursorLeftWindow; +#[derive(Clone)] pub struct InputButtons { // the u64 as the key is the hashed value of T. this makes it easier to // search for a button and see its state diff --git a/src/math/transform.rs b/src/math/transform.rs index 31b6039..5e213f2 100755 --- a/src/math/transform.rs +++ b/src/math/transform.rs @@ -56,7 +56,17 @@ impl Transform { /// Get the forward vector of the Transform. pub fn forward(&self) -> Vec3 { - self.rotation * ONE_V3 + (self.rotation * -Vec3::Z).normalize() + } + + /// Get the left vector of the Transform. + pub fn left(&self) -> Vec3 { + (self.rotation * Vec3::X).normalize() + } + + /// Get the up vector of the Transform. + pub fn up(&self) -> Vec3 { + (self.rotation * Vec3::Y).normalize() } /// Rotate this transform using a Quaternion diff --git a/src/render/camera.rs b/src/render/camera.rs index 37be4ab..fa72afd 100755 --- a/src/render/camera.rs +++ b/src/render/camera.rs @@ -66,13 +66,13 @@ impl RenderCamera { match camera.mode { CameraProjectionMode::Perspective => { let position = camera.transform.translation; - let target = camera.transform.rotation * glam::Vec3::new(0.0, 0.0, -1.0); - let target = target.normalize(); + let forward = camera.transform.forward(); + let up = camera.transform.up(); let view = glam::Mat4::look_to_rh( position, - target, - glam::Vec3::new(0.0, 1.0, 0.0) + forward, + up ); let proj = glam::Mat4::perspective_rh_gl(camera.fov.to_radians(), self.aspect, self.znear, self.zfar);