feat: update to bevy 13.2; rework input collection system
This commit is contained in:
@@ -11,10 +11,10 @@ inspector-egui = ["reflect", "dep:bevy-inspector-egui"]
|
||||
|
||||
[dependencies]
|
||||
bevy-inspector-egui = { version = "0.22.1", optional = true }
|
||||
bevy_app = "0.12.1"
|
||||
bevy_derive = "0.12.1"
|
||||
bevy_ecs = "0.12.1"
|
||||
bevy_input = "0.12.1"
|
||||
bevy_app = "0.13.2"
|
||||
bevy_derive = "0.13.2"
|
||||
bevy_ecs = "0.13.2"
|
||||
bevy_input = "0.13.2"
|
||||
bevy_reflect = { version = "0.12.1", optional = true }
|
||||
bevy_utils = "0.12.1"
|
||||
log = "0.4.20"
|
||||
|
||||
+801
-557
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ wayland = ["bevy/wayland"]
|
||||
windows = ["bevy/bevy_winit"]
|
||||
|
||||
[dependencies]
|
||||
bevy = { version = "0.12.1", default-features = false, features = [
|
||||
bevy = { version = "0.13.2", default-features = false, features = [
|
||||
"bevy_asset",
|
||||
"bevy_text",
|
||||
"bevy_ui",
|
||||
|
||||
+9
-9
@@ -5,11 +5,11 @@
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -20,11 +20,11 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1707092692,
|
||||
"narHash": "sha256-ZbHsm+mGk/izkWtT4xwwqz38fdlwu7nUUKXTOmm4SyE=",
|
||||
"lastModified": 1712163089,
|
||||
"narHash": "sha256-Um+8kTIrC19vD4/lUCN9/cU9kcOsD1O1m+axJqQPyMM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "faf912b086576fd1a15fca610166c98d47bc667e",
|
||||
"rev": "fd281bd6b7d3e32ddfa399853946f782553163b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -51,11 +51,11 @@
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1707358215,
|
||||
"narHash": "sha256-Nuhi8KEJ2e+2nTimSyEIPqN5eh7ECVWd+AnPXG6L+SY=",
|
||||
"lastModified": 1712196778,
|
||||
"narHash": "sha256-SOiwCr2HtmYpw8OvQQVRPtiCBWwndbIoPqtsamZK3J8=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "dd917bb1b67fc049fd56fe6de70266a9ab74a4aa",
|
||||
"rev": "20e7895d1873cc64c14a9f024a8e04f5824bed28",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = '1.72.0'
|
||||
channel = '1.76.0'
|
||||
|
||||
@@ -11,7 +11,7 @@ use bevy_controls::{
|
||||
plugin::ControlsPlugin,
|
||||
resource::{
|
||||
ActivationMode, ActivationOptions, Binding, BindingCondition, BindingConfig, Bindings,
|
||||
ButtonCombination, Controls, InputType, InputValue, Keyboard, OptionsMode, PlayerInputs,
|
||||
ButtonCombination, Controls, InputType, InputValue, OptionsMode, PlayerActions,
|
||||
},
|
||||
};
|
||||
use bevy_controls_derive::{Action, GameState};
|
||||
@@ -37,19 +37,19 @@ enum MyGameState {
|
||||
#[derive(Resource, Default, Clone, Debug)]
|
||||
struct MyInputsContainer {
|
||||
// When the game does not provide multiplayer, one field is enough
|
||||
player_inputs: PlayerInputs<MyAction>,
|
||||
player_inputs: PlayerActions<MyAction>,
|
||||
}
|
||||
|
||||
impl InputsContainer<MyAction> for MyInputsContainer {
|
||||
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<MyAction>> + 'a> {
|
||||
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerActions<MyAction>> + 'a> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn me<'a>(&'a self) -> Option<&'a PlayerInputs<MyAction>> {
|
||||
Some(&self.player_inputs)
|
||||
fn me<'a>(&'a self) -> Option<&'a PlayerActions<MyAction>> {
|
||||
Some(&self.player_inputs)
|
||||
}
|
||||
|
||||
fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerInputs<MyAction>> {
|
||||
fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerActions<MyAction>> {
|
||||
Some(&mut self.player_inputs)
|
||||
}
|
||||
}
|
||||
@@ -78,12 +78,7 @@ fn main() {
|
||||
BindingConfig::new(Bindings::new(vec![
|
||||
// this way input will work only on latin layout only on `A`, because it uses `Keyboard::KeyCode`
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::A),
|
||||
))),
|
||||
// this way input will work only on any layout on same button, 35 is `H` for `us` layout or
|
||||
// `О` for `ru` layout, because it uses `Keyboard::ScanCode`
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::ScanCode(ScanCode(35)),
|
||||
KeyCode::KeyA,
|
||||
)))
|
||||
.with_condition(BindingCondition::InGameState(MyGameState::InGame)),
|
||||
]))
|
||||
@@ -94,37 +89,32 @@ fn main() {
|
||||
// the rest will be simplified
|
||||
.with(
|
||||
MyAction::Back,
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::S)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(36))),
|
||||
]),
|
||||
BindingConfig::from_vec(vec![Binding::from_single(InputType::Keyboard(
|
||||
KeyCode::KeyS,
|
||||
))]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Forward,
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::W)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(37))),
|
||||
]),
|
||||
BindingConfig::from_vec(vec![Binding::from_single(InputType::Keyboard(
|
||||
KeyCode::KeyW,
|
||||
))]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Right,
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::D)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(38))),
|
||||
]),
|
||||
BindingConfig::from_vec(vec![Binding::from_single(InputType::Keyboard(
|
||||
KeyCode::KeyD,
|
||||
))]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Up,
|
||||
BindingConfig::from_bind(Binding::from_single(InputType::from_key_code(
|
||||
KeyCode::Space,
|
||||
))),
|
||||
BindingConfig::from_bind(Binding::from_single(InputType::Keyboard(KeyCode::Space))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Down,
|
||||
BindingConfig::from_bind(Binding::from_chord(vec![
|
||||
InputType::from_key_code(KeyCode::ShiftLeft),
|
||||
InputType::from_key_code(KeyCode::Space),
|
||||
])),
|
||||
BindingConfig::from_bind(Binding::from_single(
|
||||
InputType::Keyboard(KeyCode::ShiftLeft),
|
||||
//InputType::Keyboard(KeyCode::Space),
|
||||
)),
|
||||
)
|
||||
.build(),
|
||||
),
|
||||
|
||||
@@ -6,13 +6,13 @@ use bevy_inspector_egui::inspector_options::InspectorOptionsType;
|
||||
use strum::IntoEnumIterator;
|
||||
// #[cfg(all(feature = "reflect", feature = "serialize"))]
|
||||
// use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
|
||||
use bevy_controls_macros::{cfg_feature_trait_bounds, supertraits};
|
||||
use bevy_controls_macros::supertraits;
|
||||
#[cfg(feature = "reflect")]
|
||||
use bevy_reflect::{FromReflect, Reflect, TypePath};
|
||||
#[cfg(feature = "serialize")]
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
|
||||
use crate::resource::PlayerInputs;
|
||||
use crate::resource::PlayerActions;
|
||||
|
||||
// ===== Action =====
|
||||
// SAFETY: inspector-egui includes reflect
|
||||
@@ -52,86 +52,9 @@ pub trait InputsContainer<A: Action>:
|
||||
{
|
||||
/// The method returning an iterator over references to the PlayerInputs.
|
||||
/// Note: the use of 'a for both the method's lifetime and the returned Iterator's lifetime.
|
||||
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerInputs<A>> + 'a>;
|
||||
fn iter_inputs<'a>(&'a self) -> Box<dyn Iterator<Item = &'a PlayerActions<A>> + 'a>;
|
||||
/// The method returning an player inputs of this client.
|
||||
fn me<'a>(&'a self) -> Option<&'a PlayerInputs<A>>;
|
||||
fn me<'a>(&'a self) -> Option<&'a PlayerActions<A>>;
|
||||
/// The method returning an mutable player inputs of this client.
|
||||
fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerInputs<A>>;
|
||||
fn me_mut<'a>(&'a mut self) -> Option<&'a mut PlayerActions<A>>;
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod test {
|
||||
// use bevy_ecs::{entity::Entity, schedule::States};
|
||||
// use bevy_utils::{HashMap, prelude::default};
|
||||
// use strum_macros::EnumIter;
|
||||
|
||||
// #[cfg(feature = "serialize")]
|
||||
// use serde::{Serialize, Deserialize};
|
||||
|
||||
// use crate::{hashmap, resource::PlayerInputs, common_traits_conditions};
|
||||
|
||||
// common_traits_conditions! {
|
||||
// #[derive(Debug, Clone, PartialEq)]
|
||||
// #[cfg_attr(feature = "reflect", reflect(Resource))]
|
||||
// pub struct Lobby {
|
||||
// pub me: PlayerId,
|
||||
// pub players: HashMap<PlayerId, Player>,
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Default for Lobby {
|
||||
// fn default() -> Self {
|
||||
// Self {
|
||||
// me: PlayerId::Host,
|
||||
// players: hashmap! {
|
||||
// PlayerId::Host => Player::default()
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// common_traits_conditions! {
|
||||
// #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
|
||||
// pub enum PlayerId {
|
||||
// /// Host or alone
|
||||
// Host,
|
||||
// /// Client
|
||||
// Client(()),
|
||||
// }
|
||||
|
||||
// #[derive(Default, Debug, PartialEq, Clone)]
|
||||
// pub struct Player {
|
||||
// /// Client do not need to know about other clients
|
||||
// #[cfg_attr(feature = "serialize", serde(skip))]
|
||||
// pub inputs: PlayerInputs<Action>,
|
||||
// #[cfg_attr(feature = "serialize", serde(skip))]
|
||||
// pub entity: Option<Entity>,
|
||||
// }
|
||||
// }
|
||||
|
||||
// #[derive(Debug, PartialEq, Clone, States, Default, Hash, Eq)]
|
||||
// pub enum GameState {
|
||||
// #[default]
|
||||
// LevelEditor,
|
||||
// InGame,
|
||||
// }
|
||||
|
||||
// impl super::GameState for GameState {}
|
||||
|
||||
// // TODO: it is just plug, it must be a trait
|
||||
// /// Actions that can be performed by player
|
||||
// #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug, EnumIter)]
|
||||
// pub enum Action {
|
||||
// /// Move forward
|
||||
// LeverEditorForward,
|
||||
// /// Move backward
|
||||
// LevelEditorBackward,
|
||||
// /// Move left
|
||||
// LevelEditorLeft,
|
||||
// /// Move right
|
||||
// LevelEditorRight,
|
||||
// LevelEditorFly,
|
||||
// }
|
||||
|
||||
// impl super::Action for Action {}
|
||||
// }
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
use bevy_app::{App, Plugin, PreUpdate, Update};
|
||||
use bevy_app::{App, Plugin, PreUpdate};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::schedule::IntoSystemConfigs;
|
||||
use bevy_ecs::system::{In, IntoSystem};
|
||||
use bevy_ecs::{
|
||||
event::EventReader,
|
||||
schedule::State,
|
||||
system::{Res, ResMut},
|
||||
system::{Res, ResMut, Resource},
|
||||
};
|
||||
use bevy_input::{
|
||||
keyboard::{KeyCode, ScanCode},
|
||||
mouse::MouseButton,
|
||||
Input,
|
||||
keyboard::KeyCode,
|
||||
mouse::{MouseButton, MouseMotion, MouseScrollUnit, MouseWheel},
|
||||
ButtonInput,
|
||||
};
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
use crate::{
|
||||
contract::{Action, GameState, InputsContainer},
|
||||
@@ -43,13 +48,20 @@ impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> ControlsPlugin<A, Ic, Gs>
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Resource, Default, Debug, Deref, DerefMut)]
|
||||
struct TrigeredInputs(HashMap<InputType, InputValue>);
|
||||
|
||||
impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> Plugin for ControlsPlugin<A, Ic, Gs> {
|
||||
fn build(&self, app: &mut App) {
|
||||
app
|
||||
.insert_resource(self.controls.clone())
|
||||
.init_resource::<Ic>()
|
||||
.add_state::<Gs>()
|
||||
.add_systems(PreUpdate, Self::collect_inputs);
|
||||
.init_resource::<TrigeredInputs>()
|
||||
.insert_state::<Gs>(Gs::default())
|
||||
.add_systems(
|
||||
PreUpdate,
|
||||
Self::collect_inputs.pipe(Self::fill_players_inputs),
|
||||
);
|
||||
|
||||
#[cfg(feature = "reflect")]
|
||||
app.register_type::<Controls<A, Gs>>();
|
||||
@@ -57,83 +69,106 @@ impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> Plugin for ControlsPlugin
|
||||
}
|
||||
|
||||
impl<A: Action, Ic: InputsContainer<A>, Gs: GameState> ControlsPlugin<A, Ic, Gs> {
|
||||
// Separate collecting and filling is necessary becouse order of complicate imputs in future
|
||||
fn collect_inputs(
|
||||
keyboard_input_keycode: Res<Input<KeyCode>>,
|
||||
keyboard_input_scancode: Res<Input<ScanCode>>,
|
||||
) {
|
||||
|
||||
let a: Vec<(InputType, InputValue)> = vec![];
|
||||
for key in keyboard_input_keycode.get_pressed() {
|
||||
|
||||
keyboard_button: Res<ButtonInput<KeyCode>>,
|
||||
mouse_buttons: Res<ButtonInput<MouseButton>>,
|
||||
mut scroll_evr: EventReader<MouseWheel>,
|
||||
mut motion_evr: EventReader<MouseMotion>,
|
||||
// mut collected_inputs: ResMut<TrigeredInputs>,
|
||||
) -> TrigeredInputs {
|
||||
let mut collected_inputs = TrigeredInputs(HashMap::new());
|
||||
for key in keyboard_button.get_pressed() {
|
||||
collected_inputs.insert(InputType::Keyboard(*key), InputValue::Boolean(true));
|
||||
}
|
||||
|
||||
// buttons.get_just_released()
|
||||
|
||||
for button in mouse_buttons.get_pressed() {
|
||||
collected_inputs.insert(
|
||||
InputType::Mouse(MouseInput::Button(*button)),
|
||||
InputValue::Boolean(true),
|
||||
);
|
||||
}
|
||||
|
||||
for ev in motion_evr.read() {
|
||||
collected_inputs.insert(
|
||||
InputType::Mouse(MouseInput::Axis(AxisName::Horizontal)),
|
||||
InputValue::Float(ev.delta.x),
|
||||
);
|
||||
collected_inputs.insert(
|
||||
InputType::Mouse(MouseInput::Axis(AxisName::Vertical)),
|
||||
InputValue::Float(ev.delta.y),
|
||||
);
|
||||
}
|
||||
|
||||
for ev in scroll_evr.read() {
|
||||
match ev.unit {
|
||||
MouseScrollUnit::Line => {
|
||||
collected_inputs.insert(
|
||||
InputType::Mouse(MouseInput::Wheel(AxisName::Horizontal)),
|
||||
InputValue::Float(ev.x),
|
||||
);
|
||||
collected_inputs.insert(
|
||||
InputType::Mouse(MouseInput::Wheel(AxisName::Vertical)),
|
||||
InputValue::Float(ev.y),
|
||||
);
|
||||
}
|
||||
MouseScrollUnit::Pixel => {
|
||||
panic!("I'm do not accept you to use touch pad in my game");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collected_inputs
|
||||
}
|
||||
|
||||
fn fill_players_inputs() {}
|
||||
// TODO: ! Zero out values that did not arrive
|
||||
fn fill_players_inputs(
|
||||
In(collected_inputs): In<TrigeredInputs>,
|
||||
mut inputs_container: ResMut<Ic>,
|
||||
controls: Res<Controls<A, Gs>>,
|
||||
game_state: Res<State<Gs>>,
|
||||
) {
|
||||
if let Some(inputs) = inputs_container.me_mut() {
|
||||
// TODO: only on controls change
|
||||
let mut action_binding_pairs: Vec<(&A, &BindingConfig<Gs>, &Binding<Gs>)> = Vec::new();
|
||||
for (action, config) in controls.iter() {
|
||||
for binding in config.bindings.iter() {
|
||||
action_binding_pairs.push((action, config, binding));
|
||||
}
|
||||
}
|
||||
|
||||
// /// Process all hard inputs and bindings to update [`PlayerInputs`]
|
||||
// fn save_input(
|
||||
// keyboard_input_keycode: Res<Input<KeyCode>>,
|
||||
// keyboard_input_scancode: Res<Input<ScanCode>>,
|
||||
// mouse_input: Res<Input<MouseButton>>,
|
||||
// mut inputs_container: ResMut<Ic>,
|
||||
// controls: Res<Controls<A, Gs>>,
|
||||
// game_state: Res<State<Gs>>,
|
||||
// ) {
|
||||
// // get current client inputs
|
||||
// if let Some(inputs) = inputs_container.me_mut() {
|
||||
// for (action, config) in controls.iter() {
|
||||
// 'bindings_loop: for binding in config.bindings.iter() {
|
||||
// // check binding conditions
|
||||
// for condition in &binding.conditions {
|
||||
// match condition {
|
||||
// BindingCondition::InGameState(state) => {
|
||||
// if *state != *game_state.get() {
|
||||
// continue 'bindings_loop;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// log::trace!("action binding {:?} {:?} in condition", action, binding);
|
||||
//
|
||||
// // check inputs & mark actions
|
||||
// match &binding.input {
|
||||
// ButtonCombination::Single(button) => match button {
|
||||
// InputType::Keyboard(Keyboard::KeyCode(key)) => {
|
||||
// if keyboard_input_keycode.pressed(*key) {
|
||||
// inputs.forced_set(*action, true);
|
||||
// break; // when on binding trigered no sence check another
|
||||
// }
|
||||
// inputs.forced_set(*action, false); // FIXME: this is happening on every pass so maybe too frequently
|
||||
// }
|
||||
// InputType::Keyboard(Keyboard::ScanCode(code)) => {
|
||||
// log::trace!("presed?: {:?}", keyboard_input_scancode.pressed(*code));
|
||||
// log::trace!("active");
|
||||
// if keyboard_input_scancode.pressed(*code) {
|
||||
// inputs.forced_set(*action, true);
|
||||
// break; // when on binding trigered no sence check another
|
||||
// }
|
||||
// inputs.forced_set(*action, false); // FIXME: this is happening on every pass so maybe too frequently
|
||||
// }
|
||||
// InputType::Mouse(input) => match input {
|
||||
// MouseInput::Axis(_axis) => {
|
||||
// todo!();
|
||||
// }
|
||||
// MouseInput::Button(button) => {
|
||||
// if !mouse_input.get_pressed().any(|b| b == button) {
|
||||
// continue 'bindings_loop;
|
||||
// }
|
||||
// }
|
||||
// MouseInput::Wheel(_axis) => {
|
||||
// todo!();
|
||||
// }
|
||||
// },
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// log::error!("cannot find me in inputs container")
|
||||
// }
|
||||
// }
|
||||
action_binding_pairs.sort_by(|a, b| b.2.input.len().cmp(&a.2.input.len()));
|
||||
|
||||
'bindings_loop: for (action, config, binding) in action_binding_pairs.iter() {
|
||||
// check binding conditions
|
||||
for condition in &binding.conditions {
|
||||
match condition {
|
||||
BindingCondition::InGameState(state) => {
|
||||
if *state != *game_state.get() {
|
||||
continue 'bindings_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//log::info!("{:#?}", collected_inputs);
|
||||
//log::info!("{:#?}", action_binding_pairs[0]);
|
||||
|
||||
match &binding.input {
|
||||
ButtonCombination::Single(input_type) => {
|
||||
if collected_inputs.contains_key(&*input_type) {
|
||||
inputs.forced_set(**action, true);
|
||||
} else {
|
||||
inputs.forced_set(**action, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: print onece
|
||||
log::warn!("cannot find me in inputs container");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::error;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::system::Resource;
|
||||
use bevy_input::{
|
||||
keyboard::{KeyCode, ScanCode},
|
||||
keyboard::KeyCode,
|
||||
mouse::MouseButton,
|
||||
};
|
||||
#[cfg(feature = "inspector-egui")]
|
||||
@@ -200,42 +200,27 @@ impl<A: Action> PlayerActions<A> {
|
||||
}
|
||||
|
||||
common_traits_conditions! {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum InputType {
|
||||
Keyboard(Keyboard),
|
||||
Keyboard(KeyCode),
|
||||
Mouse(MouseInput),
|
||||
// TODO: Gamepad(GamepadButtonType),
|
||||
// TODO: Touch screen
|
||||
// TODO: TouchPad inputs
|
||||
}
|
||||
}
|
||||
|
||||
impl InputType {
|
||||
pub fn from_key_code(key_code: KeyCode) -> Self {
|
||||
InputType::Keyboard(Keyboard::KeyCode(key_code))
|
||||
}
|
||||
pub fn from_scan_code(scan_code: ScanCode) -> Self {
|
||||
InputType::Keyboard(Keyboard::ScanCode(scan_code))
|
||||
}
|
||||
}
|
||||
|
||||
common_traits_conditions! {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Keyboard {
|
||||
KeyCode(KeyCode),
|
||||
ScanCode(ScanCode),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum MouseInput {
|
||||
Button(MouseButton),
|
||||
Axis(AxisName),
|
||||
Wheel(AxisName)
|
||||
// TODO: CursorPosition
|
||||
// TODO: TouchPad inputs
|
||||
}
|
||||
|
||||
/// Name of axis
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
|
||||
pub enum AxisName {
|
||||
Horizontal,
|
||||
Vertical,
|
||||
@@ -311,7 +296,19 @@ common_traits_conditions! {
|
||||
// /// Chord is a combination of buttons that must be pressed at the same time
|
||||
// Chord(Vec<InputType>),
|
||||
}
|
||||
}
|
||||
|
||||
impl ButtonCombination {
|
||||
pub fn len(&self) -> usize {
|
||||
use crate::resource::ButtonCombination::*;
|
||||
match self {
|
||||
Single(_) => 1
|
||||
// TODO: Chord
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
common_traits_conditions! {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum BindingCondition<Gs: GameState> {
|
||||
/// During specific game state
|
||||
@@ -572,7 +569,7 @@ impl<A: Action, Gs: GameState> ControlsBuilder<A, Gs> {
|
||||
// or make sure that you have only one Menufor<'a> Action<'a> with the same name in the Menufor<'a> Action<'a>s
|
||||
assert!(validate_hash_map(&**self));
|
||||
|
||||
std::mem::take(&mut self)
|
||||
std::mem::take(&mut self) // TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user