From 75d98aad6b0e356480d32c8400ae5f073b1a7b7b Mon Sep 17 00:00:00 2001 From: Michael Huebner Date: Tue, 11 Mar 2025 13:33:01 +0100 Subject: [PATCH] First draft for FreeSpaceControl --- .../src/scene/general/free_space_control.rs | 158 ++++++++++++++++++ engine/src/scene/general/mod.rs | 17 +- engine/src/scene/general/prelude.rs | 1 + 3 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 engine/src/scene/general/free_space_control.rs diff --git a/engine/src/scene/general/free_space_control.rs b/engine/src/scene/general/free_space_control.rs new file mode 100644 index 0000000..5797beb --- /dev/null +++ b/engine/src/scene/general/free_space_control.rs @@ -0,0 +1,158 @@ +use context::prelude::cgmath::*; +use std::time::Duration; + +pub struct FreeSpaceControlSettings { + /// m / s^2 + pub max_forward_acceleration: f32, + /// m / s^2 + pub max_forward_deceleration: f32, + + /// m / s^2 + /// up, down, left, right + pub max_strafe_acceleration: f32, + + /// ° / s^2 + pub max_yaw_acceleration: Deg, + /// ° / s^2 + pub max_pitch_acceleration: Deg, + /// ° / s^2 + pub max_roll_acceleration: Deg, +} + +impl Default for FreeSpaceControlSettings { + fn default() -> Self { + Self { + max_forward_acceleration: 50.0, + max_forward_deceleration: 10.0, + + max_strafe_acceleration: 5.0, + + max_yaw_acceleration: Deg(5.0), + max_pitch_acceleration: Deg(5.0), + max_roll_acceleration: Deg(5.0), + } + } +} + +pub struct FreeSpaceControl { + settings: FreeSpaceControlSettings, + + /// (yaw, pitch, roll) + rotation: Vector3>, + position: Vector3, + + /// (yaw, pitch, roll) + input_rotation: Vector3, + /// (forward, sideward, upward) + input_position: Vector3, + + last_update: Option, +} + +impl FreeSpaceControl { + pub fn new(settings: FreeSpaceControlSettings) -> Self { + Self { + settings, + + rotation: vec3(Deg(0.0), Deg(0.0), Deg(0.0)), + position: Vector3::zero(), + + input_rotation: Vector3::zero(), + input_position: Vector3::zero(), + + last_update: None, + } + } + + pub fn replace_settings(&mut self, settings: FreeSpaceControlSettings) { + self.settings = settings; + } + + pub fn set_throttle(&mut self, throttle: f32) { + debug_assert!(-1.0 <= throttle); + debug_assert!(throttle <= 1.0); + + self.input_position.y = throttle; + } + + pub fn set_left_right_strafe(&mut self, strafe: f32) { + debug_assert!(-1.0 <= strafe); + debug_assert!(strafe <= 1.0); + + self.input_position.x = strafe; + } + + pub fn set_up_down_strafe(&mut self, strafe: f32) { + debug_assert!(-1.0 <= strafe); + debug_assert!(strafe <= 1.0); + + self.input_position.z = strafe; + } + + pub fn set_yaw(&mut self, yaw: f32) { + debug_assert!(-1.0 <= yaw); + debug_assert!(yaw <= 1.0); + + self.input_rotation.x = yaw; + } + + pub fn set_pitch(&mut self, pitch: f32) { + debug_assert!(-1.0 <= pitch); + debug_assert!(pitch <= 1.0); + + self.input_rotation.y = pitch; + } + + pub fn set_roll(&mut self, roll: f32) { + debug_assert!(-1.0 <= roll); + debug_assert!(roll <= 1.0); + + self.input_rotation.z = roll; + } + + fn add_rotation(&mut self, rotation: Vector3>) { + self.rotation.x += rotation.x; + self.rotation.y += rotation.y; + self.rotation.z += rotation.z; + } + + fn rotation_matrix(&self) -> Matrix3 { + Matrix3::from_angle_z(self.rotation.x) + * Matrix3::from_angle_y(self.rotation.y) + * Matrix3::from_angle_x(self.rotation.z) + } + + pub fn update(&mut self, now: Duration) -> Option> { + let diff = match self.last_update { + Some(last_update) => now - last_update, + None => { + self.last_update = Some(now); + return None; + } + }; + + let (rotation_changes, position_changes) = self.calculate_tick_changes(diff); + + let rotated_position_changes = self.rotation_matrix() * position_changes; + self.add_rotation(rotation_changes); + self.position += rotated_position_changes; + + Some(Matrix4::from(self.rotation_matrix()) * Matrix4::from_translation(self.position)) + } + + #[rustfmt::skip] + fn calculate_tick_changes(&self, diff: Duration) -> (Vector3>, Vector3) { + ( + vec3( + Deg(diff.as_secs_f32() * self.input_rotation.x * self.settings.max_yaw_acceleration.0), + Deg(diff.as_secs_f32() * self.input_rotation.y * self.settings.max_pitch_acceleration.0), + Deg(diff.as_secs_f32() * self.input_rotation.z * self.settings.max_roll_acceleration.0), + ), + vec3( + diff.as_secs_f32() * self.input_position.x * self.settings.max_strafe_acceleration, + diff.as_secs_f32() * self.input_position.y * if self.input_position.y > 0.0 { self.settings.max_forward_acceleration } else { self.settings.max_forward_deceleration }, + diff.as_secs_f32() * self.input_position.z * self.settings.max_strafe_acceleration, + ) + ) + } +} diff --git a/engine/src/scene/general/mod.rs b/engine/src/scene/general/mod.rs index 021a44c..3040092 100644 --- a/engine/src/scene/general/mod.rs +++ b/engine/src/scene/general/mod.rs @@ -1,14 +1,9 @@ pub mod camera; - -pub mod light; - -pub mod validcommandbuffer; - -pub mod view; - -pub mod top_down_camera_control; - -pub mod view_frustum; - pub mod free_camera_control; +pub mod free_space_control; +pub mod light; pub mod prelude; +pub mod top_down_camera_control; +pub mod validcommandbuffer; +pub mod view; +pub mod view_frustum; diff --git a/engine/src/scene/general/prelude.rs b/engine/src/scene/general/prelude.rs index 375cf62..8d83f86 100644 --- a/engine/src/scene/general/prelude.rs +++ b/engine/src/scene/general/prelude.rs @@ -1,5 +1,6 @@ pub use super::camera::*; pub use super::free_camera_control::*; +pub use super::free_space_control::*; pub use super::light::*; pub use super::top_down_camera_control::*; pub use super::validcommandbuffer::*;