leafwing-studios / leafwing-input-manager Goto Github PK
View Code? Open in Web Editor NEWA straightforward stateful input manager for the Bevy game engine.
License: Apache License 2.0
A straightforward stateful input manager for the Bevy game engine.
License: Apache License 2.0
Particularly demonstrate how to handle gamepad mapping and registration.
This will require us to:
IntoEnumIterator
trait, rolling the iter
method into Actionlike
EnumIter
macro to the Actionlike
enum.In exchange, users will be able to remove the strum
dependency, and reduce their derive spam by one trait.
While we're at it, we should add a upper_bound() -> u32
trait, unblocking #39.
Incidentally, this strategy will enable users to manually implement the trait for non-enum action types, which can be very useful for open-ended sets of inputs.
Show an example with the player and camera each having a separate ActionState and InputMap.
Doesn't advance due to lack of cursor. Implement IntoIterator instead.
Ran the ui-driven-action
example and pressed right.
Move right.
Move left.
Seems to trigger no matter what method is used. InputMap::pressed may be broken. Add more tests!
Looking for how to disable handling inputs for states/entities not currently active without removing components.
Unknown
Currently Undocumented.
Actionlike needs to manually implemented. Manual impls always suck when they don't contain any logic.
Derive macro
InputMap
and ActionState
could both use some serious doc tests to demonstrate usage and verify correctness.
Save and load my input map settings to a file.
Implement Serialize
and Deserialize
for the InputMap
, ActionState
and ActionDiff
types.
Use a Nintendo Switch style "press L and R" to register prompt.
Click something, set its ActionState
!
Check "how pressed" my triggers etc are in an input-agnostic fashion.
Call action_state.value(action)
and receive a f32.
Follow standard convention in bevyengine/bevy#3419 for what values should be returned for trivial virtual buttons.
We could consider storing other, arbitrarily complex information on here, using the data encoded on the Action
enum.
enum Action{
Jump(Height),
Attack,
Move(Position),
}
And then return the actual value stored in the matching variant
Ties in to the thoughts about durations in #37, and may provide the richness needed for #35.
Support sequences of button-presses to trigger an action.
Add a Sequence(Vec<Button>)
variant to UserInput
.
This should be triggered if those keys are pressed in sequence.
Related to but distinct from #5.
Should be much faster, easier to work with, and will enforce uniqueness.
E.g. have both Ctrl+R
and R
bound, but only trigger want to trigger Ctrl+R
hotkey.
Perhaps trigger on release in case of conflict?
Specify dedicated modifier keys?
Looking to use input mapping for a multiple modality game. The three modes my prototype offers are in states and are top-down flight, top-down tilemap, and a Grimrock style cellular 3d. Each mode has its own control scheme often sharing common keys for similar actions.
Key | Flying | Walking | Hacking |
---|---|---|---|
W | Thrust | MoveNorth | Advance |
A | TurnLeft | MoveWest | RotateLeft |
S | Reverse | MoveSouth | Retreat |
D | TurnRight | MoveEast | RotateRight |
Q | StrafeLeft | ||
E | StrageRight | ||
Space | FirePrimary | ||
Alt | FireSecondary | ||
1 | Slot1 | Slot1 | Slot1 |
2 | Slot2 | Slot2 | Slot2 |
3 | Slot3 | Slot3 | Slot3 |
4 | Slot4 | Slot4 | Slot4 |
Suggestion on Discord was to instantiate multiple copies of the plugin and create an enumeration for each game mode input map.
Currently undocumented.
Drive action state by clicking buttons in the UI.
Lay out what an ideal solution would look like, from a user-facing perspective.
Create an example to document directly modifying ActionState
based on events sent by UI clicks.
Create an UserInput
variant that can store arbitrary events, which can be read or processed.
However, this is less than useful: any system that this plugin create cannot have automatic access to the corresponding event: work is required at compile time.
Once bevyengine/bevy#142 is solved this should be revisited: dynamically adding systems to correspond to new mapped event types may be feasible.
0.1.2
ArchLinux
I tried the following example from docs:
leafwing-input-manager/src/lib.rs
Lines 116 to 141 in c5e59de
But it crashes if I add a state and call a single update. So the documentation test is valid only because update()
is not called.
Plugin runs only in specified state
thread 'main' panicked at 'Resource requested by <leafwing_input_manager::InputManagerPlugin<input_test::PlayerAction, input_test::GameState> as bevy_app::plugin::Plugin>::build::{{closure}} does not exist: input_test::GameState', /home/gena/.cargo/
registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/system_param.rs:326:17
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Minimal example that should work, but crashes:
main.rs
There are three main use patterns for this:
bevy_input
if necessary
Eventually this should support:
Should be tackled together with #4.
enum VirtualButtonStatus{
JustPressed,
Held(Duration),
JustReleased,
Released,
}
This allows users to track things like "press for X seconds" much more naturally, and simplifies the lifecycles in a natural way.
Some users may want to use fewer max bindings per action: commonly 3 or 6. This saves memory.
Other users may want a truly absurd number of max bindings.
Allow users to configure the max bindings per entity.
Specify the max bindings in the Actionlike
trait as an associate constant.
However, this requires the use of the rather-incomplete associated_const_generics
feature.
Pass this in as a const generic on InputMap
. This causes massive generic pollution of the API.
Add a const generic to InputMap
but set a default. This causes other APIs to not work unless they use the default value.
Somehow pass this in as an as a feature flag or something? Really unclear how this could work nicely.
Had to remove when investigating #30.
Commonly, users want to be able to save and load input mapping presets.
These are frequently input-type specific, which does not play nice with the current design of InputMap
.
I should be able to:
This will allows full stack allocation.
We can access the total number of actions with https://docs.rs/strum/latest/strum/trait.EnumCount.html, but we're blocked on rust-lang/rust#60551.
Use more sophisticated input patterns to drive a change in the ActionState
:
Being able to swap these out are commonly important for accessiblity.
The UserInput
enum is extended to support these modes.
This is automatically detected by the plugin's systems.
Users can freely swap between the various input modes.
22d6708e67aea588fcc1ad121e86debf4af0652c
Ubuntu 20.10
cargo run --example minimal
The example works
The example panics:
thread 'main' panicked at 'Resource requested by leafwing_input_manager::systems::update_action_state<minimal::Action> does not exist: bevy_input::input::Input<bevy_input::gamepad::GamepadButton>', /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/system_param.rs:326:17
stack backtrace:
0: rust_begin_unwind
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/std/src/panicking.rs:498:5
1: core::panicking::panic_fmt
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/core/src/panicking.rs:107:14
2: <bevy_ecs::system::system_param::ResState<T> as bevy_ecs::system::system_param::SystemParamFetch>::get_param::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/system_param.rs:326:17
3: core::option::Option<T>::unwrap_or_else
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/core/src/option.rs:787:21
4: <bevy_ecs::system::system_param::ResState<T> as bevy_ecs::system::system_param::SystemParamFetch>::get_param
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/system_param.rs:323:22
5: <(P0,P1,P2,P3) as bevy_ecs::system::system_param::SystemParamFetch>::get_param
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/system_param.rs:1212:20
6: <Func as bevy_ecs::system::function_system::SystemParamFunction<(),Out,(F0,F1,F2,F3),()>>::run
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/function_system.rs:514:37
7: <bevy_ecs::system::function_system::FunctionSystem<In,Out,Param,Marker,F> as bevy_ecs::system::system::System>::run_unsafe
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/system/function_system.rs:442:19
8: bevy_ecs::schedule::executor_parallel::ParallelExecutor::prepare_systems::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/schedule/executor_parallel.rs:214:30
9: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/core/src/future/mod.rs:80:19
10: async_executor::Executor::spawn::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:144:13
11: <core::future::from_generator::GenFuture<T> as core::future::future::Future>::poll
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/core/src/future/mod.rs:80:19
12: async_task::raw::RawTask<F,T,S>::run
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/async-task-4.0.3/src/raw.rs:489:20
13: async_executor::Executor::try_tick
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/async-executor-1.4.1/src/lib.rs:181:17
14: bevy_tasks::task_pool::TaskPool::scope::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.6.0/src/task_pool.rs:222:21
15: std::thread::local::LocalKey<T>::try_with
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/std/src/thread/local.rs:399:16
16: std::thread::local::LocalKey<T>::with
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/std/src/thread/local.rs:375:9
17: bevy_tasks::task_pool::TaskPool::scope
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_tasks-0.6.0/src/task_pool.rs:169:9
18: <bevy_ecs::schedule::executor_parallel::ParallelExecutor as bevy_ecs::schedule::executor::ParallelSystemExecutor>::run_systems
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/schedule/executor_parallel.rs:122:9
19: <bevy_ecs::schedule::stage::SystemStage as bevy_ecs::schedule::stage::Stage>::run
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/schedule/stage.rs:850:17
20: bevy_ecs::schedule::Schedule::run_once
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/schedule/mod.rs:344:13
21: <bevy_ecs::schedule::Schedule as bevy_ecs::schedule::stage::Stage>::run
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_ecs-0.6.0/src/schedule/mod.rs:362:21
22: bevy_app::app::App::update
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.6.0/src/app.rs:112:9
23: <bevy_app::schedule_runner::ScheduleRunnerPlugin as bevy_app::plugin::Plugin>::build::{{closure}}::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.6.0/src/schedule_runner.rs:90:25
24: <bevy_app::schedule_runner::ScheduleRunnerPlugin as bevy_app::plugin::Plugin>::build::{{closure}}
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.6.0/src/schedule_runner.rs:115:47
25: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/alloc/src/boxed.rs:1708:9
26: bevy_app::app::App::run
at /home/rezural/.cargo/registry/src/github.com-1ecc6299db9ec823/bevy_app-0.6.0/src/app.rs:130:9
27: minimal::main
at ./examples/minimal.rs:6:5
28: core::ops::function::FnOnce::call_once
at /rustc/db9d1b20bba1968c1ec1fc49616d4742c1725b4b/library/core/src/ops/function.rs:227:5
UserInput::Chord
stores a slow, heap-allocated HashSet despite its tiny size.
Store buttons
in an ArrayVec
with a tiny max length instead.
Read from an object created in #50, and send gamepad events when certain features are met.
Unclear whether this is best done as a feature or example.
Only implement where the underlying type is Copy.
The HashMap-style API is familiar, but not very ergonomic.
Perhaps from_iter
?
This is an unusual feature, and can be hard to visually represent.
Combine keycodes (or other inputs), and only register an action if the particular combination is pressed.
Add an enum variant(s) to ButtonLike
to allow for combinations of buttons to be added.
Create From
impls for tuples of ButtonLike.
Look at https://github.com/lightsoutgames/bevy_input_actionmap and https://github.com/sadpython/bevy_advanced_input for inspiration.
Allows for fast reinsertion at the same point.
Many games want to allow up to one or two bindings for each input mode.
Create an alternative discretized API for controlling input mappings.
Allow users to specify maximum bindings total XOR maximum bindings per input mode.
Related to #22, as these bindings will typically be limited to a single device.
Related to #21, as these bindings will typically be limited to one or two inputs for display purposes.
Needs:
These are useful for various gameplay needs: particularly just_released
.
These should be derived from ActionState
's pressed
, in order to ensure consistent internal state despite multiple input devices.
Const generic defaults are unstable :(
We can't reasonably handle multiple players using the same computer with this library.
ActionState
and InputMap
s in a component.InputAction
using generics.InputAction
enum.InputMap
and ActionState
resources to also include player information.Player
marker.ActionState
is often player-agnostic.This is complex and critical logic. It needs nice asserts and real tests for robustness.
Integration tests needed:
Can't avoid heap allocation anyways because it's stored in a HashMap XD
Create an example showing how and why you might want to do this.
Chords detected within this grace period should be treated as one unit.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.