From 22b582c3f8546b85c8f59105e28071e2a400cbe7 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Sat, 6 Jan 2024 20:15:54 -0500 Subject: [PATCH] Implement axises to input actions, use input actions with the free fly camera --- examples/testbed/src/free_fly_camera.rs | 67 +++++++----- examples/testbed/src/main.rs | 53 ++++++---- lyra-game/src/input/action.rs | 131 +++++++++++++++++++----- 3 files changed, 177 insertions(+), 74 deletions(-) diff --git a/examples/testbed/src/free_fly_camera.rs b/examples/testbed/src/free_fly_camera.rs index 26991b2..dd6b4c2 100644 --- a/examples/testbed/src/free_fly_camera.rs +++ b/examples/testbed/src/free_fly_camera.rs @@ -2,7 +2,7 @@ use std::{ops::Deref, ptr::NonNull}; use lyra_engine::{ game::Game, - input::{InputButtons, KeyCode, MouseMotion}, + input::{InputButtons, KeyCode, MouseMotion, ActionHandler}, math::{Quat, Vec3, EulerRot}, plugin::Plugin, ecs::{system::{System, IntoSystem}, world::World, Access, Component}, DeltaTime, EventQueue, scene::CameraComponent, }; @@ -21,8 +21,8 @@ impl Default for FreeFlyCamera { Self { speed: 4.0, slow_speed_factor: 0.25, - look_speed: 0.09, - mouse_sensitivity: 0.4, + look_speed: 0.3, + mouse_sensitivity: 1.0, look_with_keys: false, } } @@ -50,15 +50,19 @@ impl System for FreeFlyCameraPlugin { let delta_time = **world.get_resource::(); - let events = world - .try_get_resource::() - .and_then(|q| q.read_events::()); + let handler = world.get_resource::(); - let keys = world - .try_get_resource::>() - .map(|r| r.deref().clone()); + /* if let Some(look_x) = handler.get_axis_modifier("look_left_right") { + camera_rot.x += look_x; + } - if let Some(keys) = keys.as_ref() { + if let Some(look_y) = handler.get_axis_modifier("look_up_down") { + camera_rot.y += look_y; + } */ + + + + /* if let Some(keys) = keys.as_ref() { if keys.is_pressed(KeyCode::Left) { camera_rot.y += 1.0; } @@ -82,7 +86,7 @@ impl System for FreeFlyCameraPlugin { if keys.is_pressed(KeyCode::Q) { camera_rot.z += 1.0; } - } + } */ for (mut cam, fly) in world .view_iter::<(&mut CameraComponent, &FreeFlyCamera)>() @@ -92,22 +96,15 @@ impl System for FreeFlyCameraPlugin { let up = Vec3::Y; // handle camera movement - if let Some(keys) = keys.as_ref() { + /* if let Some(keys) = keys.as_ref() { let mut velocity = Vec3::ZERO; - if keys.is_pressed(KeyCode::A) { - velocity -= left; + + if let Some(m) = handler.get_pressed_modifier("forward_backward") { + velocity += m * forward; } - 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 let Some(m) = handler.get_pressed_modifier("left_right") { + velocity += m * left; } if keys.is_pressed(KeyCode::C) { @@ -127,15 +124,33 @@ impl System for FreeFlyCameraPlugin { cam.transform.translation += velocity.normalize() * temp; } + } */ + + let mut velocity = Vec3::ZERO; + + let move_y = handler.get_axis_modifier("up_down").unwrap_or(0.0); + let move_x = handler.get_axis_modifier("left_right").unwrap_or(0.0); + let move_z = handler.get_axis_modifier("forward_backward").unwrap_or(0.0); + 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 } // handle camera rotation - if let Some(mut events) = events.clone() { + /* if let Some(mut events) = events.clone() { while let Some(motion) = events.pop_front() { camera_rot.x -= motion.delta.y * fly.mouse_sensitivity; camera_rot.y -= motion.delta.x * fly.mouse_sensitivity; } - } + } */ + + let motion_x = handler.get_axis_modifier("look_left_right").unwrap_or(0.0); + let motion_y = handler.get_axis_modifier("look_up_down").unwrap_or(0.0); + camera_rot.y -= motion_x * fly.mouse_sensitivity; + camera_rot.x -= motion_y * fly.mouse_sensitivity; if camera_rot != Vec3::ZERO { let look_velocity = camera_rot * fly.look_speed * delta_time; diff --git a/examples/testbed/src/main.rs b/examples/testbed/src/main.rs index 6db0d68..283ce6e 100644 --- a/examples/testbed/src/main.rs +++ b/examples/testbed/src/main.rs @@ -1,11 +1,10 @@ use std::ptr::NonNull; -use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin}, game::Game, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, world::World, Component}, DeltaTime, scene::{TransformComponent, ModelComponent, CameraComponent}}; +use lyra_engine::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin, MouseInput, MouseAxis}, game::Game, render::{window::{CursorGrabMode, WindowOptions}, light::{PointLight, directional::DirectionalLight, SpotLight}}, change_tracker::Ct, ecs::{system::{Criteria, CriteriaSchedule, BatchedSystem, IntoSystem}, world::World, Component}, DeltaTime, scene::{TransformComponent, ModelComponent, CameraComponent}}; use lyra_engine::assets::{ResourceManager, Model}; mod free_fly_camera; use free_fly_camera::{FreeFlyCameraPlugin, FreeFlyCamera}; -use tracing::debug; struct FixedTimestep { max_tps: u32, @@ -233,38 +232,48 @@ async fn main() { let action_handler_plugin = |game: &mut Game| { let action_handler = ActionHandler::new() .add_layout(LayoutId::from(0)) - .add_action("forward_backward", Action::new(ActionKind::Button)) - .add_action("left_right", Action::new(ActionKind::Button)) + + .add_action("forward_backward", Action::new(ActionKind::Axis)) + .add_action("left_right", Action::new(ActionKind::Axis)) + .add_action("up_down", Action::new(ActionKind::Axis)) + .add_action("look_left_right", Action::new(ActionKind::Axis)) + .add_action("look_up_down", Action::new(ActionKind::Axis)) + .add_action("look_rotate", Action::new(ActionKind::Axis)) + .add_mapping(ActionMapping::new(LayoutId::from(0), ActionMappingId::from(0)) .bind("forward_backward", &[ ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0), ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0) ]) .bind("left_right", &[ - ActionSource::Keyboard(KeyCode::A).into_binding_modifier(1.0), - ActionSource::Keyboard(KeyCode::D).into_binding_modifier(-1.0) + ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0), + ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0) + ]) + .bind("up_down", &[ + ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0), + ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0) + ]) + .bind("look_left_right", &[ + ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(), + ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0), + ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0), + //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickX)).into_binding(), + ]) + .bind("look_up_down", &[ + ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(), + ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0), + ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0), + //ActionSource::Gamepad(GamepadFormat::DualAxis, GamepadInput::Axis(GamepadAxis::RThumbstickY)).into_binding(), + ]) + .bind("look_rotate", &[ + ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0), + ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0), ]) .finish() ); - #[allow(unused_variables)] - let test_system = |world: &mut World| -> anyhow::Result<()> { - let handler = world.get_resource::(); - - if let Some(alpha) = handler.get_pressed_modifier("forward_backward") { - debug!("'forward_backward': {alpha}"); - } - - if let Some(alpha) = handler.get_pressed_modifier("left_right") { - debug!("'left_right': {alpha}"); - } - - Ok(()) - }; - game.world().add_resource(action_handler); game.with_plugin(InputActionPlugin); - //game.with_system("test_actions", test_system, &[]); }; Game::initialize().await diff --git a/lyra-game/src/input/action.rs b/lyra-game/src/input/action.rs index dad7f2e..5b52d22 100644 --- a/lyra-game/src/input/action.rs +++ b/lyra-game/src/input/action.rs @@ -1,10 +1,11 @@ use std::{collections::HashMap, ops::Deref}; +use glam::Vec2; use lyra_ecs::world::World; -use crate::{plugin::Plugin, game::GameStages}; +use crate::{plugin::Plugin, game::GameStages, EventQueue}; -use super::{Button, KeyCode, InputButtons}; +use super::{Button, KeyCode, InputButtons, MouseMotion}; #[allow(dead_code)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -55,11 +56,36 @@ pub enum GamepadInput { Axis(GamepadAxis), } +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum MouseButton { + Left, + Right, + Middle, + Other(u16), +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum MouseAxis { + X, + Y, + ScrollWheel, +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum MouseInput { + Button(MouseButton), + Axis(MouseAxis), +} + #[allow(dead_code)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum ActionSource { Keyboard(KeyCode), Gamepad(GamepadFormat, GamepadInput), + Mouse(MouseInput) } impl ActionSource { @@ -83,6 +109,7 @@ pub struct Binding { impl Binding { /// Create a binding from a Source. Uses a default value of `1.0` as the modifier. pub fn from_source(source: ActionSource) -> Self { + // TODO: Some types of input will have a default modifier, mainly axis' Self { source, modifier: 1.0, @@ -202,6 +229,8 @@ impl ActionMapping { let action_binds = self.action_binds.entry(action_label.to_string()).or_default(); action_binds.append(&mut bindings); + println!("Creating action label {}", action_label); + self } @@ -344,42 +373,92 @@ impl ActionHandler { fn actions_system(world: &mut World) -> anyhow::Result<()> { let keys = world.try_get_resource::>() .map(|r| r.deref().clone()); + let mouse_events = world + .try_get_resource::() + .and_then(|q| q.read_events::()); + //let mouse = world.try_get_resource() - if let Some(keys) = keys { + // clear the states of all axises each frame + { let mut handler = world.try_get_resource_mut::() .expect("No Input Action handler was created in the world!"); let layout = handler.layouts.get(&handler.current_layout).expect("No active layout"); let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping"); - for (action_name, binds) in mapping.action_binds.clone().iter() { // TODO: dont clone - let mut new_state = None; + for (action_name, _) in mapping.action_binds.clone().iter() { + let action = handler.actions.get_mut(action_name).expect("Action name for binding is invalid!"); + if action.kind == ActionKind::Axis { + action.state = ActionState::Axis(0.0); + } + } + } + + let motion_avg = if let Some(mut mouse_events) = mouse_events { + let count = mouse_events.len(); + let mut sum = Vec2::ZERO; + while let Some(mm) = mouse_events.pop_front() { + sum += mm.delta; + } + Some(sum / count as f32) + } else { None }; - for bind in binds.iter() { - match bind.source { - ActionSource::Keyboard(key) => { - // JustPressed needs to be first, since is_pressed includes buttons that - // were just pressed. - if keys.was_just_pressed(key) { - new_state = Some(ActionState::JustPressed(bind.modifier)); - } else if keys.is_pressed(key) { - new_state = Some(ActionState::Pressed(bind.modifier)); + let mut handler = world.try_get_resource_mut::() + .expect("No Input Action handler was created in the world!"); + + let layout = handler.layouts.get(&handler.current_layout).expect("No active layout"); + let mapping = layout.mappings.get(&layout.active_mapping).expect("No active mapping"); + + for (action_name, binds) in mapping.action_binds.clone().iter() { + let action = handler.actions.get_mut(action_name).expect("Action name for binding is invalid!"); + let mut new_state = None; + + for bind in binds.iter() { + match bind.source { + ActionSource::Keyboard(key) => if let Some(keys) = &keys { + // JustPressed needs to be first, since is_pressed includes buttons that + // were just pressed. + match action.kind { + ActionKind::Button => { + if keys.was_just_pressed(key) { + new_state = Some(ActionState::JustPressed(bind.modifier)); + } else if keys.is_pressed(key) { + new_state = Some(ActionState::Pressed(bind.modifier)); + } + }, + ActionKind::Axis => { + if keys.is_pressed(key) { + new_state = Some(ActionState::Axis(bind.modifier)); + } + } + } + + }, + ActionSource::Gamepad(_, _) => todo!(), + ActionSource::Mouse(m) => match m { + MouseInput::Button(_) => todo!(), + MouseInput::Axis(a) => if let Some(motion_avg) = motion_avg { + match a { + MouseAxis::X => { + new_state = Some(ActionState::Axis(motion_avg.x)); + }, + MouseAxis::Y => { + new_state = Some(ActionState::Axis(motion_avg.y)); + }, + MouseAxis::ScrollWheel => todo!(), } }, - ActionSource::Gamepad(_, _) => todo!(), - } + }, } + } - let action = handler.actions.get_mut(action_name).expect("Action name for binding is invalid!"); - - if let Some(new_state) = new_state { - action.state = new_state; - } else { - match action.state { - ActionState::Idle => {}, - ActionState::JustReleased => action.state = ActionState::Idle, - _ => action.state = ActionState::JustReleased, - } + if let Some(new_state) = new_state { + action.state = new_state; + } else if action.kind == ActionKind::Button { + match action.state { + ActionState::Idle => {}, + ActionState::JustReleased => action.state = ActionState::Idle, + _ => action.state = ActionState::JustReleased, } } }