Fix querying resources in fn systems, create CommonActionLabels, more code cleanup of free fly camera
This commit is contained in:
parent
265752ee76
commit
ac24d1f913
|
@ -1,12 +1,19 @@
|
|||
use std::ptr::NonNull;
|
||||
|
||||
use lyra_engine::{
|
||||
game::Game,
|
||||
input::ActionHandler,
|
||||
input::{ActionHandler, CommonActionLabel},
|
||||
math::{Quat, Vec3, EulerRot},
|
||||
plugin::Plugin, ecs::{system::{System, IntoSystem}, world::World, Access, Component}, DeltaTime, scene::CameraComponent,
|
||||
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,
|
||||
|
@ -41,74 +48,58 @@ impl FreeFlyCamera {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct FreeFlyCameraPlugin;
|
||||
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;
|
||||
|
||||
impl System for FreeFlyCameraPlugin {
|
||||
fn execute(&mut self, mut world: NonNull<World>) -> anyhow::Result<()> {
|
||||
let world = unsafe { world.as_mut() };
|
||||
let delta_time = **world.get_resource::<DeltaTime>();
|
||||
let handler = world.get_resource::<ActionHandler>();
|
||||
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);
|
||||
|
||||
for (mut cam, fly) in world
|
||||
.view_iter::<(&mut CameraComponent, &FreeFlyCamera)>()
|
||||
{
|
||||
let forward = cam.transform.forward();
|
||||
let left = cam.transform.left();
|
||||
let up = Vec3::Y;
|
||||
let mut velocity = Vec3::ZERO;
|
||||
velocity += move_y * up;
|
||||
velocity += move_x * left;
|
||||
velocity += move_z * forward;
|
||||
|
||||
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);
|
||||
|
||||
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("look_left_right").unwrap_or(0.0);
|
||||
let motion_y = handler.get_axis_modifier("look_up_down").unwrap_or(0.0);
|
||||
let motion_z = handler.get_axis_modifier("look_rotate").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);
|
||||
}
|
||||
if velocity != Vec3::ZERO {
|
||||
cam.transform.translation += velocity.normalize() * fly.speed * delta_time; // TODO: speeding up
|
||||
}
|
||||
|
||||
Ok(())
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
fn world_access(&self) -> lyra_engine::ecs::Access {
|
||||
Access::Write
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl IntoSystem<()> for FreeFlyCameraPlugin {
|
||||
type System = Self;
|
||||
|
||||
fn into_system(self) -> Self::System {
|
||||
self
|
||||
}
|
||||
}
|
||||
/// 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", FreeFlyCameraPlugin, &[]);
|
||||
game.with_system("free_fly_camera_system", free_fly_camera_controller, &[]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,21 @@
|
|||
use std::ptr::NonNull;
|
||||
|
||||
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::{math::{self, Vec3}, math::Transform, input::{KeyCode, ActionHandler, Action, ActionKind, LayoutId, ActionMapping, ActionSource, ActionMappingId, InputActionPlugin, MouseInput, MouseAxis, CommonActionLabel}, 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};
|
||||
|
||||
#[derive(Clone, Copy, Hash, Debug)]
|
||||
pub enum ActionLabel {
|
||||
MoveForwardBackward,
|
||||
MoveLeftRight,
|
||||
MoveUpDown,
|
||||
LookLeftRight,
|
||||
LookUpDown,
|
||||
LookRoll,
|
||||
}
|
||||
|
||||
struct FixedTimestep {
|
||||
max_tps: u32,
|
||||
fixed_time: f32,
|
||||
|
@ -233,47 +243,59 @@ async fn main() {
|
|||
let action_handler = ActionHandler::new()
|
||||
.add_layout(LayoutId::from(0))
|
||||
|
||||
.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_action(CommonActionLabel::MoveForwardBackward, Action::new(ActionKind::Axis))
|
||||
.add_action(CommonActionLabel::MoveLeftRight, Action::new(ActionKind::Axis))
|
||||
.add_action(CommonActionLabel::MoveUpDown, Action::new(ActionKind::Axis))
|
||||
.add_action(CommonActionLabel::LookLeftRight, Action::new(ActionKind::Axis))
|
||||
.add_action(CommonActionLabel::LookUpDown, Action::new(ActionKind::Axis))
|
||||
.add_action(CommonActionLabel::LookRoll, Action::new(ActionKind::Axis))
|
||||
|
||||
.add_mapping(ActionMapping::new(LayoutId::from(0), ActionMappingId::from(0))
|
||||
.bind("forward_backward", &[
|
||||
.bind(CommonActionLabel::MoveForwardBackward, &[
|
||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0)
|
||||
])
|
||||
.bind("left_right", &[
|
||||
.bind(CommonActionLabel::MoveLeftRight, &[
|
||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0)
|
||||
])
|
||||
.bind("up_down", &[
|
||||
.bind(CommonActionLabel::MoveUpDown, &[
|
||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0)
|
||||
])
|
||||
.bind("look_left_right", &[
|
||||
.bind(CommonActionLabel::LookLeftRight, &[
|
||||
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", &[
|
||||
.bind(CommonActionLabel::LookUpDown, &[
|
||||
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", &[
|
||||
.bind(CommonActionLabel::LookRoll, &[
|
||||
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_axis_modifier("look_rotate") {
|
||||
debug!("'look_rotate': {alpha}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}; */
|
||||
|
||||
game.world().add_resource(action_handler);
|
||||
game.with_plugin(InputActionPlugin);
|
||||
//game.with_system("input_test", test_system, &[]);
|
||||
};
|
||||
|
||||
Game::initialize().await
|
||||
|
|
|
@ -79,7 +79,7 @@ impl<R: ResourceObject> AsQuery for QueryResource<R> {
|
|||
}
|
||||
|
||||
/// A struct used for querying resources from the World.
|
||||
pub struct Res<'a, T>(Ref<'a, T>);
|
||||
pub struct Res<'a, T>(pub(crate) Ref<'a, T>);
|
||||
|
||||
impl<'a, T: ResourceObject> std::ops::Deref for Res<'a, T> {
|
||||
type Target = T;
|
||||
|
@ -167,7 +167,7 @@ impl<R: ResourceObject> AsQuery for QueryResourceMut<R> {
|
|||
}
|
||||
|
||||
/// A struct used for querying resources from the World.
|
||||
pub struct ResMut<'a, T>(RefMut<'a, T>);
|
||||
pub struct ResMut<'a, T>(pub(crate) RefMut<'a, T>);
|
||||
|
||||
impl<'a, T: ResourceObject> std::ops::Deref for ResMut<'a, T> {
|
||||
type Target = T;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{ptr::NonNull, marker::PhantomData, cell::{Ref, RefMut}};
|
||||
use std::{ptr::NonNull, marker::PhantomData};
|
||||
|
||||
use crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery}};
|
||||
use crate::{world::World, Access, ResourceObject, query::{Query, View, AsQuery, ResMut, Res}};
|
||||
|
||||
use super::{System, IntoSystem};
|
||||
|
||||
|
@ -184,12 +184,12 @@ pub struct ResourceArgFetcher<R: ResourceObject> {
|
|||
phantom: PhantomData<fn() -> R>
|
||||
}
|
||||
|
||||
impl<'a, R: ResourceObject> FnArg for Ref<'a, R> {
|
||||
impl<'a, R: ResourceObject> FnArg for Res<'a, R> {
|
||||
type Fetcher = ResourceArgFetcher<R>;
|
||||
}
|
||||
|
||||
impl<R: ResourceObject> FnArgFetcher for ResourceArgFetcher<R> {
|
||||
type Arg<'a> = Ref<'a, R>;
|
||||
type Arg<'a> = Res<'a, R>;
|
||||
|
||||
fn new() -> Self {
|
||||
ResourceArgFetcher {
|
||||
|
@ -199,7 +199,7 @@ impl<R: ResourceObject> FnArgFetcher for ResourceArgFetcher<R> {
|
|||
|
||||
unsafe fn get<'a>(&mut self, world: NonNull<World>) -> Self::Arg<'a> {
|
||||
let world = world.as_ref();
|
||||
world.get_resource::<R>()
|
||||
Res(world.get_resource::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,12 +207,12 @@ pub struct ResourceMutArgFetcher<R: ResourceObject> {
|
|||
phantom: PhantomData<fn() -> R>
|
||||
}
|
||||
|
||||
impl<'a, R: ResourceObject> FnArg for RefMut<'a, R> {
|
||||
impl<'a, R: ResourceObject> FnArg for ResMut<'a, R> {
|
||||
type Fetcher = ResourceMutArgFetcher<R>;
|
||||
}
|
||||
|
||||
impl<R: ResourceObject> FnArgFetcher for ResourceMutArgFetcher<R> {
|
||||
type Arg<'a> = RefMut<'a, R>;
|
||||
type Arg<'a> = ResMut<'a, R>;
|
||||
|
||||
fn new() -> Self {
|
||||
ResourceMutArgFetcher {
|
||||
|
@ -222,15 +222,15 @@ impl<R: ResourceObject> FnArgFetcher for ResourceMutArgFetcher<R> {
|
|||
|
||||
unsafe fn get<'a>(&mut self, world: NonNull<World>) -> Self::Arg<'a> {
|
||||
let world = world.as_ref();
|
||||
world.get_resource_mut::<R>()
|
||||
ResMut(world.get_resource_mut::<R>())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::{ptr::NonNull, cell::RefMut};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
use crate::{tests::{Vec2, Vec3}, world::World, query::{QueryBorrow, View}};
|
||||
use crate::{tests::{Vec2, Vec3}, world::World, query::{QueryBorrow, View, ResMut}};
|
||||
use super::{System, IntoSystem};
|
||||
|
||||
struct SomeCounter(u32);
|
||||
|
@ -355,8 +355,10 @@ mod tests {
|
|||
world.spawn((Vec2::rand(), Vec3::rand()));
|
||||
world.add_resource(SomeCounter(0));
|
||||
|
||||
let test_system = |mut counter: RefMut<SomeCounter>| -> anyhow::Result<()> {
|
||||
counter.0 += 10;
|
||||
let test_system = |mut counter: ResMut<SomeCounter>| -> anyhow::Result<()> {
|
||||
// .0 is twice here since ResMut's tuple field is pub(crate).
|
||||
// Users wont need to do this
|
||||
counter.0.0 += 10;
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
@ -374,10 +376,12 @@ mod tests {
|
|||
world.spawn((Vec2::rand(), ));
|
||||
world.add_resource(SomeCounter(0));
|
||||
|
||||
let test_system = |mut counter: RefMut<SomeCounter>, view: View<QueryBorrow<Vec2>>| -> anyhow::Result<()> {
|
||||
let test_system = |mut counter: ResMut<SomeCounter>, view: View<QueryBorrow<Vec2>>| -> anyhow::Result<()> {
|
||||
for v2 in view.into_iter() {
|
||||
println!("Got v2 at '{:?}'", v2);
|
||||
counter.0 += 1;
|
||||
// .0 is twice here since ResMut's tuple field is pub(crate).
|
||||
// Users wont need to do this
|
||||
counter.0.0 += 1;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::{collections::HashMap, ops::Deref};
|
||||
use std::{collections::HashMap, ops::Deref, hash::{Hash, DefaultHasher, Hasher}, fmt::Debug};
|
||||
|
||||
use glam::Vec2;
|
||||
use lyra_ecs::world::World;
|
||||
|
@ -7,6 +7,54 @@ use crate::{plugin::Plugin, game::GameStages, EventQueue};
|
|||
|
||||
use super::{Button, KeyCode, InputButtons, MouseMotion};
|
||||
|
||||
pub trait ActionLabel: Debug {
|
||||
/// Returns a unique hash of the label.
|
||||
fn label_hash(&self) -> u64;
|
||||
}
|
||||
|
||||
impl<T: Hash + Debug> ActionLabel for T {
|
||||
fn label_hash(&self) -> u64 {
|
||||
let mut s = DefaultHasher::new();
|
||||
self.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ActionLabelWrapper(String, u64);
|
||||
|
||||
impl Debug for ActionLabelWrapper {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_str(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl ActionLabel for ActionLabelWrapper {
|
||||
fn label_hash(&self) -> u64 {
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: ActionLabel + Hash> From<A> for ActionLabelWrapper {
|
||||
fn from(value: A) -> Self {
|
||||
let lbl = format!("{:?}", value);
|
||||
Self(lbl, value.label_hash())
|
||||
}
|
||||
}
|
||||
|
||||
/// Some commonly used action labels.
|
||||
///
|
||||
/// The built-in systems uses these labels
|
||||
#[derive(Clone, Copy, Hash, Debug)]
|
||||
pub enum CommonActionLabel {
|
||||
MoveForwardBackward,
|
||||
MoveLeftRight,
|
||||
MoveUpDown,
|
||||
LookLeftRight,
|
||||
LookUpDown,
|
||||
LookRoll,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
pub enum GamepadFormat {
|
||||
|
@ -204,7 +252,7 @@ impl From<u32> for ActionMappingId {
|
|||
pub struct ActionMapping {
|
||||
layout: LayoutId,
|
||||
id: ActionMappingId,
|
||||
action_binds: HashMap<String, Vec<Binding>>,
|
||||
action_binds: HashMap<u64, Vec<Binding>>,
|
||||
}
|
||||
|
||||
impl ActionMapping {
|
||||
|
@ -221,16 +269,17 @@ impl ActionMapping {
|
|||
/// If the action is not in this layout, this will panic!
|
||||
///
|
||||
/// Parameters:
|
||||
/// * `action_label` - The label corresponding to the action in this Layout.
|
||||
/// * `action` - The label corresponding to the action in this Layout.
|
||||
/// * `bind` - The Binding to add to the Action.
|
||||
pub fn bind(mut self, action_label: &str, bindings: &[Binding]) -> Self {
|
||||
pub fn bind<L>(mut self, action: L, bindings: &[Binding]) -> Self
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let mut bindings = bindings.to_vec();
|
||||
|
||||
let action_binds = self.action_binds.entry(action_label.to_string()).or_default();
|
||||
let action_binds = self.action_binds.entry(action.label_hash()).or_default();
|
||||
action_binds.append(&mut bindings);
|
||||
|
||||
println!("Creating action label {}", action_label);
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -257,7 +306,7 @@ impl ActionMapping {
|
|||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct ActionHandler {
|
||||
pub actions: HashMap<String, Action>,
|
||||
pub actions: HashMap<u64, Action>,
|
||||
pub layouts: HashMap<LayoutId, Layout>,
|
||||
pub current_layout: LayoutId,
|
||||
pub current_mapping: ActionMappingId,
|
||||
|
@ -274,8 +323,11 @@ impl ActionHandler {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn add_action(mut self, label: &str, action: Action) -> Self {
|
||||
self.actions.insert(label.to_string(), action);
|
||||
pub fn add_action<L>(mut self, label: L, action: Action) -> Self
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
self.actions.insert(label.label_hash(), action);
|
||||
|
||||
self
|
||||
}
|
||||
|
@ -290,9 +342,12 @@ impl ActionHandler {
|
|||
/// Returns true if the action is pressed (or was just pressed).
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn is_action_pressed(&self, action_name: &str) -> bool {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn is_action_pressed<L>(&self, action: L) -> bool
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
matches!(action.state, ActionState::Pressed(_) | ActionState::JustPressed(_))
|
||||
}
|
||||
|
@ -300,9 +355,12 @@ impl ActionHandler {
|
|||
/// Returns true if the action was just pressed.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn was_action_just_pressed(&self, action_name: &str) -> bool {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn was_action_just_pressed<L>(&self, action: L) -> bool
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
matches!(action.state, ActionState::JustPressed(_))
|
||||
}
|
||||
|
@ -310,9 +368,12 @@ impl ActionHandler {
|
|||
/// Returns true if the action was just released.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn was_action_just_released(&self, action_name: &str) -> bool {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn was_action_just_released<L>(&self, action: L) -> bool
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
matches!(action.state, ActionState::JustReleased)
|
||||
}
|
||||
|
@ -320,9 +381,12 @@ impl ActionHandler {
|
|||
/// Returns an action's state.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn get_action_state(&self, action_name: &str) -> ActionState {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn get_action_state<L>(&self, action: L) -> ActionState
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
action.state
|
||||
}
|
||||
|
@ -331,9 +395,12 @@ impl ActionHandler {
|
|||
/// Returns `None` if the action's state is not `ActionState::Pressed` or `ActionState::JustPressed`.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn get_pressed_modifier(&self, action_name: &str) -> Option<f32> {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn get_pressed_modifier<L>(&self, action: L) -> Option<f32>
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
match action.state {
|
||||
ActionState::Pressed(v) | ActionState::JustPressed(v) => Some(v),
|
||||
|
@ -345,9 +412,12 @@ impl ActionHandler {
|
|||
/// Returns `None` if the action's state is not `ActionState::JustPressed`.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn get_just_pressed_modifier(&self, action_name: &str) -> Option<f32> {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn get_just_pressed_modifier<L>(&self, action: L) -> Option<f32>
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
match action.state {
|
||||
ActionState::JustPressed(v) => Some(v),
|
||||
|
@ -359,9 +429,12 @@ impl ActionHandler {
|
|||
/// Returns `None` if the action's state is not `ActionState::Axis`.
|
||||
///
|
||||
/// This will panic if the action name does not correspond to an action.
|
||||
pub fn get_axis_modifier(&self, action_name: &str) -> Option<f32> {
|
||||
let action = self.actions.get(action_name)
|
||||
.unwrap_or_else(|| panic!("Action {action_name} was not found"));
|
||||
pub fn get_axis_modifier<L>(&self, action: L) -> Option<f32>
|
||||
where
|
||||
L: ActionLabel
|
||||
{
|
||||
let action = self.actions.get(&action.label_hash())
|
||||
.unwrap_or_else(|| panic!("Action {action:?} was not found"));
|
||||
|
||||
match action.state {
|
||||
ActionState::Axis(v) => Some(v),
|
||||
|
@ -386,8 +459,8 @@ fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
|||
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, _) in mapping.action_binds.clone().iter() {
|
||||
let action = handler.actions.get_mut(action_name).expect("Action name for binding is invalid!");
|
||||
for (action, _) in mapping.action_binds.clone().iter() {
|
||||
let action = handler.actions.get_mut(action).expect("Action name for binding is invalid!");
|
||||
if action.kind == ActionKind::Axis {
|
||||
action.state = ActionState::Axis(0.0);
|
||||
}
|
||||
|
@ -409,8 +482,8 @@ fn actions_system(world: &mut World) -> anyhow::Result<()> {
|
|||
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!");
|
||||
for (action_lbl, binds) in mapping.action_binds.clone().iter() {
|
||||
let action = handler.actions.get_mut(action_lbl).expect("Action name for binding is invalid!");
|
||||
let mut new_state = None;
|
||||
|
||||
for bind in binds.iter() {
|
||||
|
|
Loading…
Reference in New Issue