Implement axises to input actions, use input actions with the free fly camera

This commit is contained in:
SeanOMik 2024-01-06 20:15:54 -05:00
parent 6242abb35b
commit 22b582c3f8
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
3 changed files with 177 additions and 74 deletions

View File

@ -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::<DeltaTime>();
let events = world
.try_get_resource::<EventQueue>()
.and_then(|q| q.read_events::<MouseMotion>());
let handler = world.get_resource::<ActionHandler>();
let keys = world
.try_get_resource::<InputButtons<KeyCode>>()
.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;

View File

@ -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::<ActionHandler>();
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

View File

@ -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::<InputButtons<KeyCode>>()
.map(|r| r.deref().clone());
let mouse_events = world
.try_get_resource::<EventQueue>()
.and_then(|q| q.read_events::<MouseMotion>());
//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::<ActionHandler>()
.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::<ActionHandler>()
.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,
}
}
}