Coder Social home page Coder Social logo

leafwing-input-manager's People

Contributors

0hypercube avatar 100-tomatojuice avatar aceeri avatar adtennant avatar alice-i-cecile avatar alradish avatar ant59 avatar athemathmo avatar benfrankel avatar cbournhonesque avatar chaosteil avatar dependabot[bot] avatar emmiasilk avatar irate-devil avatar johanhelsing avatar mrkiffie avatar ndarilek avatar nosideeffects avatar pulau-komodo avatar rparrett avatar shatur avatar shute052 avatar signalwalker avatar spectria-limina avatar squ1rr avatar striezel avatar therawmeatball avatar timjentzsch avatar waywardmonkeys avatar wesleyclements avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

leafwing-input-manager's Issues

Remove strum dependency

This will require us to:

  1. Removing the IntoEnumIterator trait, rolling the iter method into Actionlike
  2. Add the 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.

Input handling seems broken

What you did

Ran the ui-driven-action example and pressed right.

What you expected to happen

Move right.

What actually happened

Move left.

Additional information

Seems to trigger no matter what method is used. InputMap::pressed may be broken. Add more tests!

Disabling InputMaps for inactive states

What problem did the developer encounter?

Looking for how to disable handling inputs for states/entities not currently active without removing components.

What was the fix?

Unknown

How could this be better documented?

Currently Undocumented.

Add derive macro for Actionlike

Which feature is frustrating to use or confusing?

Actionlike needs to manually implemented. Manual impls always suck when they don't contain any logic.

Expectation

Derive macro

Add doc tests

InputMap and ActionState could both use some serious doc tests to demonstrate usage and verify correctness.

Store and return values for virtual buttons

What problem does this solve?

Check "how pressed" my triggers etc are in an input-agnostic fashion.

What solution would you like?

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.

[Optional] What alternatives have you considered?

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

Related work

Ties in to the thoughts about durations in #37, and may provide the richness needed for #35.

Support for sequences

What problem does this solve?

Support sequences of button-presses to trigger an action.

What solution would you like?

Add a Sequence(Vec<Button>) variant to UserInput.

This should be triggered if those keys are pressed in sequence.

Related work

Related to but distinct from #5.

Multi Modal Input Maps.

What problem did the developer encounter?

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.

Example

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

What was the fix?

Suggestion on Discord was to instantiate multiple copies of the plugin and create an enumeration for each game mode input map.

How could this be better documented?

Currently undocumented.

Drive action state from UI

What problem does this solve?

Drive action state by clicking buttons in the UI.

What solution would you like?

Lay out what an ideal solution would look like, from a user-facing perspective.

How could this be implemented?

Create an example to document directly modifying ActionState based on events sent by UI clicks.

What alternatives have you considered?

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.

Related work

Once bevyengine/bevy#142 is solved this should be revisited: dynamically adding systems to correspond to new mapped event types may be feasible.

Function run_in state causes crash

Version

0.1.2

Operating system & version

ArchLinux

What you did

I tried the following example from docs:

/// Creates a version of this plugin that will only run in the specified `state_variant`
///
/// # Example
/// ```rust
/// use bevy::prelude::*;
/// use leafwing_input_manager::*;
/// use strum::EnumIter;
///
/// #[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug, EnumIter)]
/// enum PlayerAction {
/// // Movement
/// Up,
/// Down,
/// Left,
/// Right,
/// }
///
/// #[derive(Debug, Clone, Eq, PartialEq, Hash)]
/// enum GameState {
/// Playing,
/// Paused,
/// Menu,
/// }
///
/// App::new().add_plugin(InputManagerPlugin::<PlayerAction, GameState>::run_in_state(GameState::Playing));
/// ```

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.

What you expected to happen

Plugin runs only in specified state

What actually happened

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

Additional information

Minimal example that should work, but crashes:
main.rs

Handle 2-dimensional analogue input

There are three main use patterns for this:

  1. Partition the analog space into digital buttons
    • Handle with a mapping API that sets thresholds/boundaries for the values
  2. Map analog values into actions, but still use the raw analog value for something (like smoothly changing walk/run on an analog stick)
    • Actually a special case of 1: You map onto an action, but then get back the analog value that generated that action
      • This can be done with reverse mapping, or with forward propagation
    • Destructuring this value ain't gonna happen
    • But we can return out the values from the virtual button if we store it
    • We actually don't need to return the value itself, just the user input that triggered it (since then the caller can look up the correct value themselves)
    • Requires #76
  3. Mapping analog values to an action simply does not make sense (flight stick tilt)
    • Not our problem- can add helper features to bevy_input if necessary
      • In particular, "get a Vec2 from a particular axis" is an extremely common operation that is unnecessarily painful

Eventually this should support:

  • all gamepad axes
  • touch emulated joysticks
  • mouse emulated joysticks

Store state for an each ActionState explicitly

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.

Allow users to configure the maximum number of bindings

What problem does this solve?

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.

What solution would you like?

Allow users to configure the max bindings per entity.

How could this be implemented?

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.

[Optional] What alternatives have you considered?

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.

Related work

Had to remove when investigating #30.

Provide helper methods for working with preset inputs

Which feature is frustrating to use or confusing?

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.

Expectation

I should be able to:

  1. Extract all input mappings of a particular type.
  2. Clear all input mappings of a particular type.
  3. Overwrite all input mappings of a particular type.

Support more sophisticated input patterns

What problem does this solve?

Use more sophisticated input patterns to drive a change in the ActionState:

  • press-and-hold
  • toggle
  • analog stick taps
  • gestures
  • touch inputs

Being able to swap these out are commonly important for accessiblity.

What solution would you like?

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.

Running examples panics with missing resource error

Version

22d6708e67aea588fcc1ad121e86debf4af0652c

Operating system & version

Ubuntu 20.10

What you did

cargo run --example minimal

What you expected to happen

The example works

What actually happened

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

Additional information

Use an ArrayVec for Chords

Which code could be improved?

UserInput::Chord stores a slow, heap-allocated HashSet despite its tiny size.

How should this be changed?

Store buttons in an ArrayVec with a tiny max length instead.

Allow users to limit the maximum number of input bindings for each input mode

What problem does this solve?

Many games want to allow up to one or two bindings for each input mode.

What solution would you like?

Create an alternative discretized API for controlling input mappings.

Allow users to specify maximum bindings total XOR maximum bindings per input mode.

Context

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.

Add arpeggios

Needs:

  • internal state on InputMap (related to #48)
  • timeout detection

Support released and just_released states

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.

Support local multiplayer

Problem

We can't reasonably handle multiple players using the same computer with this library.

Options

  1. Always store the ActionState and InputMaps in a component.
  2. Optionally store these in components.
  3. Use multiple related copies of InputAction using generics.
  4. Double etc. the size of the InputAction enum.
  5. Expand the InputMap and ActionState resources to also include player information.

Initial evaluation

  1. Possibly viable. Probably forces us to have a second generic to pass in the game's Player marker.
  2. More viable: ActionState is often player-agnostic.
  3. Terrible: matching won't work correctly.
  4. See 3.
  5. A bit messy: having to constantly manage this is a nuisance in single-player games.

Add tests for ArraySet

This is complex and critical logic. It needs nice asserts and real tests for robustness.

Add integration tests

Integration tests needed:

  • Keyboard, mouse and joystick inputs all work as expected in simple cases.
  • Clicking a button with an ActionStateDriver works correctly.
  • Game runs in a state correctly (#46).

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.