generated from 2ndbeam/bevy-template
feat: Added input system
- Added input plugin to manage controls config - Added tests for casting InputMap to InputAsset and backwards
This commit is contained in:
parent
10afe6fd08
commit
ae7bfd7c27
5 changed files with 471 additions and 3 deletions
164
Cargo.lock
generated
164
Cargo.lock
generated
|
|
@ -23,6 +23,10 @@ name = "accesskit"
|
|||
version = "0.21.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf203f9d3bd8f29f98833d1fbef628df18f759248a547e7e01cfbf63cda36a99"
|
||||
dependencies = [
|
||||
"enumn",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "accesskit_consumer"
|
||||
|
|
@ -167,6 +171,12 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.102"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
version = "0.5.1"
|
||||
|
|
@ -334,6 +344,7 @@ dependencies = [
|
|||
"bevy_derive",
|
||||
"bevy_ecs",
|
||||
"bevy_reflect",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -548,6 +559,21 @@ dependencies = [
|
|||
"wgpu-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_common_assets"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad51a6e9def88caadc4ce2a5670382d6ff19fa1e7e7af934326c5c0b376bdd9f"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bevy_app",
|
||||
"bevy_asset",
|
||||
"bevy_reflect",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"toml 0.9.12+spec-1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bevy_core_pipeline"
|
||||
version = "0.18.0"
|
||||
|
|
@ -836,6 +862,7 @@ dependencies = [
|
|||
"bevy_reflect",
|
||||
"derive_more",
|
||||
"log",
|
||||
"serde",
|
||||
"smol_str",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
|
@ -1002,6 +1029,7 @@ dependencies = [
|
|||
"bytemuck",
|
||||
"derive_more",
|
||||
"hexasphere",
|
||||
"serde",
|
||||
"thiserror 2.0.18",
|
||||
"tracing",
|
||||
"wgpu-types",
|
||||
|
|
@ -1463,6 +1491,7 @@ dependencies = [
|
|||
"bevy_utils",
|
||||
"bevy_window",
|
||||
"derive_more",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"taffy",
|
||||
"thiserror 2.0.18",
|
||||
|
|
@ -2174,6 +2203,24 @@ version = "0.1.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-eq"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c2d035d21af5cde1a6f5c7b444a5bf963520a9f142e5d06931178433d7d5388"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-hash"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fdab65db9274e0168143841eb8f864a0a21f8b1b8d2ba6812bbe6024346e99e"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
|
|
@ -2211,6 +2258,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enumn"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
|
|
@ -2273,6 +2331,11 @@ name = "expedition_demo"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"bevy_common_assets",
|
||||
"bevy_input",
|
||||
"leafwing-input-manager",
|
||||
"serde",
|
||||
"toml 1.0.3+spec-1.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2911,6 +2974,34 @@ version = "1.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||
|
||||
[[package]]
|
||||
name = "leafwing-input-manager"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed83d1d7334e742aab3409782cdbb2bc96cc017df9ff342dd5aeb80eed1b784"
|
||||
dependencies = [
|
||||
"bevy",
|
||||
"dyn-clone",
|
||||
"dyn-eq",
|
||||
"dyn-hash",
|
||||
"itertools 0.14.0",
|
||||
"leafwing_input_manager_macros",
|
||||
"serde",
|
||||
"serde_flexitos",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "leafwing_input_manager_macros"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2226cb83129176a6c634f2ce0828c2c29896ea0898fc198636f98696b8056890"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lewton"
|
||||
version = "0.10.2"
|
||||
|
|
@ -4154,6 +4245,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_flexitos"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3323d093d7597660758b742dd7a1525539613f6182b306a4e1dd6e01a89bada9"
|
||||
dependencies = [
|
||||
"erased-serde",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.149"
|
||||
|
|
@ -4167,6 +4268,15 @@ dependencies = [
|
|||
"zmij",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
@ -4228,6 +4338,9 @@ name = "smallvec"
|
|||
version = "1.15.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smithay-client-toolkit"
|
||||
|
|
@ -4469,6 +4582,36 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.9.12+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime 0.7.5+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "1.0.3+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7614eaf19ad818347db24addfa201729cf2a9b6fdfd9eb0ab870fcacc606c0c"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde_core",
|
||||
"serde_spanned",
|
||||
"toml_datetime 1.0.0+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"toml_writer",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.7.5+spec-1.1.0"
|
||||
|
|
@ -4478,6 +4621,15 @@ dependencies = [
|
|||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "1.0.0+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.23.10+spec-1.0.0"
|
||||
|
|
@ -4485,20 +4637,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"toml_datetime",
|
||||
"toml_datetime 0.7.5+spec-1.1.0",
|
||||
"toml_parser",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_parser"
|
||||
version = "1.0.7+spec-1.1.0"
|
||||
version = "1.0.9+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1"
|
||||
checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4"
|
||||
dependencies = [
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_writer"
|
||||
version = "1.0.6+spec-1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.44"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,11 @@ edition = "2024"
|
|||
|
||||
[dependencies]
|
||||
bevy = { version = "0.18.0" }
|
||||
bevy_common_assets = { version = "0.15.0", features = ["toml"] }
|
||||
bevy_input = { version = "0.18.0", features = ["serde", "serialize"] }
|
||||
leafwing-input-manager = "0.20.0"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
toml = "1.0.3"
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
|
|
|||
217
src/input.rs
Normal file
217
src/input.rs
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
use std::{any::{Any, TypeId}, collections::HashMap, hash::Hash, marker::PhantomData};
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_common_assets::toml::TomlAssetPlugin;
|
||||
use leafwing_input_manager::{Actionlike, prelude::{Axislike, Buttonlike, DualAxislike, InputMap}};
|
||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||
|
||||
const INPUT_ASSET_EXTENSIONS: [&'static str; 1] = ["input.toml"];
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, Default, PartialEq, Eq)]
|
||||
pub struct MultiInput {
|
||||
pub keyboard: Option<Vec<KeyCode>>,
|
||||
pub mouse: Option<Vec<MouseButton>>,
|
||||
pub gamepad: Option<Vec<GamepadButton>>,
|
||||
}
|
||||
|
||||
impl From<MultiInput> for InputKind {
|
||||
fn from(value: MultiInput) -> Self {
|
||||
Self::Button(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[serde(untagged)]
|
||||
pub enum InputKind {
|
||||
Button(MultiInput),
|
||||
Axis(Vec<Box<dyn Axislike>>),
|
||||
DualAxis(Vec<Box<dyn DualAxislike>>),
|
||||
}
|
||||
|
||||
#[derive(Default, Deref, DerefMut, Debug, Asset, Reflect, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct InputAsset<Name>
|
||||
where Name: Sized + Hash + Eq + Reflect + TypePath + Actionlike {
|
||||
#[serde(flatten)]
|
||||
events: HashMap<Name, InputKind>,
|
||||
}
|
||||
|
||||
fn copy_keys<Name, Button>(input_map: &mut InputMap<Name>, name: &Name, buttons: &Vec<Button>)
|
||||
where Name: Sized + Hash + Eq + Reflect + TypePath + Actionlike,
|
||||
Button: Buttonlike + Clone {
|
||||
let bindings: Vec<(Name, Button)> = buttons.iter()
|
||||
.map(|k| (name.clone(), k.to_owned())).collect();
|
||||
input_map.insert_multiple(bindings);
|
||||
}
|
||||
|
||||
impl<Name> From<InputAsset<Name>> for InputMap<Name>
|
||||
where Name: Sized + Hash + Eq + Reflect + TypePath + Actionlike {
|
||||
fn from(asset: InputAsset<Name>) -> Self {
|
||||
let new_asset = (*asset).clone();
|
||||
let mut input_map = InputMap::default();
|
||||
for (name, input_kind) in new_asset.into_iter() {
|
||||
match input_kind {
|
||||
InputKind::Button(input) => {
|
||||
if let Some(buttons) = input.keyboard {
|
||||
copy_keys(&mut input_map, &name, &buttons);
|
||||
}
|
||||
if let Some(buttons) = input.mouse {
|
||||
copy_keys(&mut input_map, &name, &buttons);
|
||||
}
|
||||
if let Some(buttons) = input.gamepad {
|
||||
copy_keys(&mut input_map, &name, &buttons);
|
||||
}
|
||||
},
|
||||
InputKind::Axis(axises) => {
|
||||
for axis in axises {
|
||||
input_map.insert_axis_boxed(name.clone(), axis);
|
||||
}
|
||||
},
|
||||
InputKind::DualAxis(axises) => {
|
||||
for axis in axises {
|
||||
input_map.insert_dual_axis_boxed(name.clone(), axis);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
input_map
|
||||
}
|
||||
}
|
||||
|
||||
impl<Name> InputAsset<Name>
|
||||
where Name: Sized + Hash + Eq + Reflect + TypePath + Actionlike {
|
||||
/// This method does several things:
|
||||
/// - Replace all actions which both are contained in the [`InputAsset`] and in the [`InputMap`]
|
||||
/// and have the same "type" (e.g. [`Buttonlike`]).
|
||||
/// - Insert all actions which are not contained in the map
|
||||
/// Common usecase for this is to update default values with this asset
|
||||
pub fn replace_input_map_actions(&self, map: &mut InputMap<Name>) {
|
||||
for (name, input_kind) in self.iter() {
|
||||
match input_kind {
|
||||
InputKind::Button(input) => {
|
||||
if map.iter_buttonlike().find(|(n, _)| n == &name).is_some() {
|
||||
map.clear_action(name);
|
||||
}
|
||||
if let Some(buttons) = &input.keyboard {
|
||||
copy_keys(map, name, &buttons);
|
||||
}
|
||||
if let Some(buttons) = &input.mouse {
|
||||
copy_keys(map, name, &buttons);
|
||||
}
|
||||
if let Some(buttons) = &input.gamepad {
|
||||
copy_keys(map, name, &buttons);
|
||||
}
|
||||
},
|
||||
InputKind::Axis(axises) => {
|
||||
if map.iter_axislike().find(|(n, _)| n == &name).is_some() {
|
||||
map.clear_action(name);
|
||||
}
|
||||
for axis in axises.iter() {
|
||||
map.insert_axis_boxed(name.to_owned(), axis.to_owned());
|
||||
}
|
||||
},
|
||||
InputKind::DualAxis(axises) => {
|
||||
if map.iter_dual_axislike().find(|(n, _)| n == &name).is_some() {
|
||||
map.clear_action(name);
|
||||
}
|
||||
for axis in axises.iter() {
|
||||
map.insert_dual_axis_boxed(name.to_owned(), axis.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_multi_input_insert<T: Clone>(input_type: &mut Option<Vec<T>>, new_key: T) {
|
||||
match input_type {
|
||||
Some(key) => key.push(new_key),
|
||||
None => {
|
||||
let wrapped_new_key = Some(vec![new_key]);
|
||||
*input_type = wrapped_new_key;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl<Name> From<InputMap<Name>> for InputAsset<Name>
|
||||
where Name: Sized + Hash + Eq + Reflect + TypePath + Actionlike + Default {
|
||||
fn from(map: InputMap<Name>) -> Self {
|
||||
let mut asset: InputAsset<Name> = InputAsset::default();
|
||||
const KC_TYPE: TypeId = TypeId::of::<KeyCode>();
|
||||
const MB_TYPE: TypeId = TypeId::of::<MouseButton>();
|
||||
const GP_TYPE: TypeId = TypeId::of::<GamepadButton>();
|
||||
for (name, buttonlikes) in map.iter_buttonlike() {
|
||||
let multi_input = {
|
||||
let input_kind = match asset.get_mut(name) {
|
||||
Some(input_kind) => input_kind,
|
||||
None => {
|
||||
asset.insert(name.to_owned(), MultiInput::default().into());
|
||||
asset.get_mut(name).unwrap()
|
||||
}
|
||||
};
|
||||
let InputKind::Button(btn) = input_kind else {
|
||||
continue;
|
||||
};
|
||||
btn
|
||||
};
|
||||
for buttonlike in buttonlikes.iter() {
|
||||
let buttonlike = &(**buttonlike) as &dyn Any;
|
||||
let checked_type = buttonlike.type_id();
|
||||
if checked_type == KC_TYPE {
|
||||
let new_key = (*buttonlike).downcast_ref::<KeyCode>().unwrap().to_owned();
|
||||
try_multi_input_insert(&mut multi_input.keyboard, new_key);
|
||||
} else if checked_type == MB_TYPE {
|
||||
let new_key = (*buttonlike).downcast_ref::<MouseButton>().unwrap().to_owned();
|
||||
try_multi_input_insert(&mut multi_input.mouse, new_key);
|
||||
} else if checked_type == GP_TYPE {
|
||||
let new_key = (*buttonlike).downcast_ref::<GamepadButton>().unwrap().to_owned();
|
||||
try_multi_input_insert(&mut multi_input.gamepad, new_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (name, axislikes) in map.iter_axislike() {
|
||||
match asset.get_mut(name) {
|
||||
Some(input_kind) => {
|
||||
let InputKind::Axis(axises) = input_kind else {
|
||||
continue;
|
||||
};
|
||||
for axislike in axislikes {
|
||||
axises.push(axislike.clone());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
asset.insert(name.clone(), InputKind::Axis(axislikes.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (name, axislikes) in map.iter_dual_axislike() {
|
||||
match asset.get_mut(name) {
|
||||
Some(input_kind) => {
|
||||
let InputKind::DualAxis(axises) = input_kind else {
|
||||
continue;
|
||||
};
|
||||
for axislike in axislikes {
|
||||
axises.push(axislike.clone());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
asset.insert(name.clone(), InputKind::DualAxis(axislikes.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
asset
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct InputAssetPlugin<T> (PhantomData<T>);
|
||||
|
||||
impl<T> Plugin for InputAssetPlugin<T>
|
||||
where T: Sized + Hash + Eq + Reflect + TypePath + Actionlike + DeserializeOwned
|
||||
{
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_plugins(TomlAssetPlugin::<InputAsset<T>>::new(&INPUT_ASSET_EXTENSIONS));
|
||||
}
|
||||
}
|
||||
10
src/lib.rs
10
src/lib.rs
|
|
@ -1,10 +1,20 @@
|
|||
pub mod player;
|
||||
pub mod layout;
|
||||
pub mod input;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
pub struct ExpeditionPlugin;
|
||||
|
||||
pub enum InputActions {
|
||||
MoveLeft,
|
||||
MoveRight,
|
||||
ToggleInventory,
|
||||
Interact,
|
||||
}
|
||||
|
||||
fn camera_bundle() -> impl Bundle {
|
||||
(
|
||||
Camera2d,
|
||||
|
|
|
|||
78
src/tests.rs
Normal file
78
src/tests.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use std::any::{Any, TypeId};
|
||||
|
||||
use super::*;
|
||||
use leafwing_input_manager::prelude::*;
|
||||
|
||||
#[derive(Actionlike, Reflect, Clone, Debug, PartialEq, Eq, Hash, Default)]
|
||||
enum Action {
|
||||
#[default]
|
||||
#[actionlike(DualAxis)]
|
||||
DualAxis,
|
||||
#[actionlike(Axis)]
|
||||
SingleAxis,
|
||||
Button,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_asset_from_map() {
|
||||
let mut input_map = InputMap::default();
|
||||
input_map.insert(Action::Button, KeyCode::KeyE);
|
||||
input_map.insert(Action::Button, GamepadButton::East);
|
||||
|
||||
input_map.insert_axis(Action::SingleAxis, GamepadAxis::LeftStickX);
|
||||
input_map.insert_axis(Action::SingleAxis, VirtualAxis::ad());
|
||||
|
||||
input_map.insert_dual_axis(Action::DualAxis, GamepadStick::RIGHT);
|
||||
input_map.insert_dual_axis(Action::DualAxis, VirtualDPad::wasd());
|
||||
|
||||
let mut expected_input_asset = input::InputAsset::default();
|
||||
expected_input_asset.insert(Action::Button, input::MultiInput {
|
||||
keyboard: Some(vec![KeyCode::KeyE]),
|
||||
gamepad: Some(vec![GamepadButton::East]),
|
||||
mouse: None,
|
||||
}.into());
|
||||
expected_input_asset.insert(Action::SingleAxis, input::InputKind::Axis(vec![
|
||||
Box::new(GamepadAxis::LeftStickX),
|
||||
Box::new(VirtualAxis::ad()),
|
||||
]));
|
||||
expected_input_asset.insert(Action::DualAxis, input::InputKind::DualAxis(vec![
|
||||
Box::new(GamepadStick::RIGHT),
|
||||
Box::new(VirtualDPad::wasd()),
|
||||
]));
|
||||
|
||||
let input_asset = input::InputAsset::from(input_map);
|
||||
|
||||
assert_eq!(input_asset, expected_input_asset);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn input_map_from_asset() {
|
||||
let mut input_asset = input::InputAsset::default();
|
||||
input_asset.insert(Action::Button, input::MultiInput {
|
||||
keyboard: Some(vec![KeyCode::KeyE]),
|
||||
gamepad: Some(vec![GamepadButton::East]),
|
||||
mouse: None,
|
||||
}.into());
|
||||
input_asset.insert(Action::SingleAxis, input::InputKind::Axis(vec![
|
||||
Box::new(GamepadAxis::LeftStickX),
|
||||
Box::new(VirtualAxis::ad()),
|
||||
]));
|
||||
input_asset.insert(Action::DualAxis, input::InputKind::DualAxis(vec![
|
||||
Box::new(GamepadStick::RIGHT),
|
||||
Box::new(VirtualDPad::wasd()),
|
||||
]));
|
||||
|
||||
let mut expected_input_map = InputMap::default();
|
||||
expected_input_map.insert(Action::Button, KeyCode::KeyE);
|
||||
expected_input_map.insert(Action::Button, GamepadButton::East);
|
||||
|
||||
expected_input_map.insert_axis(Action::SingleAxis, GamepadAxis::LeftStickX);
|
||||
expected_input_map.insert_axis(Action::SingleAxis, VirtualAxis::ad());
|
||||
|
||||
expected_input_map.insert_dual_axis(Action::DualAxis, GamepadStick::RIGHT);
|
||||
expected_input_map.insert_dual_axis(Action::DualAxis, VirtualDPad::wasd());
|
||||
|
||||
let input_map = InputMap::from(input_asset);
|
||||
|
||||
assert_eq!(input_map, expected_input_map);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue