#bevy_enhanced_input
1 messages Β· Page 5 of 1
but maybe that's not the philosophy here
This is the pattern I'm following rn
it works dont get me wrong
It just gives me vibes of I'm not doing it correctly
I do think it might depend on how you view contexts. In my mind, contexts are used to separate actions based on what state an entity or the game might be in. For me, a context isn't for reusing actions necessarily but being able to bind the same input to different actions depending on the specific circumstances that exist for the context to be active.
I'm not sure if that is the philosophy of the library though.
(The multiple repeated cycle actions are missing, but you get the point :P)
I think the key might be that if multiple actions across contexts lead to different effects then they should probably be separately defined actions. If you had a cycle action that changed something in the UI that did the same thing on different entities then it makes sense to keep it the same. If the cycle action depends on specific code depending for what is being cycled, then the actions should probably be different.
I'll keep experimenting, thanks for the feedback @heady mauve
one more question b4 leaving, is there an straightforward way to have contextless actions? or actions that trigger on all contexts
(same thing called differently :/)
I don't think there are context-less actions. So if you want some action to be a global thing that can be done from anywhere it would have to be in a context on an entity that would live for the length of time you are looking for.
I'm a little confused by wanting actions that trigger on all contexts. There is context layering so you can have certain actions in a single context and then can have other contexts on the same entity also. Those other contexts could be deactivated, removed, or replaced with other contexts and as long as you leave the context with the action you want alone it should still activate as long as none of the other contexts in a higher priority consume the same input.
If I am misunderstanding your question, then perhaps you could provide an example that explains the scenario you are looking for.
It was just a question, but yeah I just want to throw in some actions mostly for trying out things
that do not go into any context per se
I just converted my entity marker (Player) into a context and will put these there
I'm trying to figure out how to use chording to combine mouse motion with a key. I.e. you press middle mouse button and move the mouse to pan the camera around.
I'm currently using the actions! macro approach from the documentation.
actions!(MainCameraControllerContext[
(
Action::<Pan>::new(),
Down::new(0.0),
Bindings::spawn((
Cardinal::wasd_keys(),
Cardinal::arrows(),
Axial::left_stick(),
)),
)
Etc.
But the other recent example of someone tackling that problem in here seems to be using a different approach. Not real sure what I need to be doing here.
For Chord you need access to the entity. See its documentation for details.
For the life of me I still cannot figure out how to get chorded inputs to work. I also can't get the action to mock. I've tried what's in the docs to the best of my understanding, and I've dug back through this thread for other discussions of it. I've tried also moving this into a different function from the one that initializes the similar portions of the context, and using the BindingOf / ActionOf relationship stuff. I'm not sure what I'm missing / doing wrong.
fn init_camera_controller(mut commands: Commands) {
commands.spawn((
Name::new("Main Camera Controller"),
MainCameraController::default(),
Transform::from_translation(Vec3::ZERO),
MainCameraControllerContext,
actions!(MainCameraControllerContext[
// Removed standard action! macro even spawn on WASD and scollwheel for discord ),
]),
Actions::<MainCameraController>::spawn(SpawnWith(|context: &mut ActionSpawner<_>| {
let rmb_chord = context
.spawn((
Action::<RMBChord>::new(),
Down::new(1.0),
bindings![MouseButton::Middle],
))
.id();
context.spawn((
Action::<Orbit>::new(),
ActionMock::new(ActionState::Fired, Vec2::ZERO, Duration::new(5, 0)),
Chord::single(rmb_chord),
bindings![Binding::mouse_motion()],
));
})),
));
}
This looks like your context is MainCameraControllerContext, but you spawn your actions for MainCameraController.
Changing that caused a panic with the note that the bundle being spawned there has duplicate components: [DebugName { name: "bevy_enhanced_input::action::relationship::Actions<tinker_3d::camera::main_camera::MainCameraControllerContext>" }]
This means you inserted 2 actions components.
I think I see this in your code above: actions!(MainCameraControllerContext...
So does that mean I need to use either the actions! macro or the method outlined in the chord example that I'm using below it and not both?
Exactly!
Okay, I'll give that a shot, thanks
Is this example wrong? It uses Fire instead of Start π€
https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/action/events/struct.Start.html#examples
Yes π
Let me quickly open a PR...
I think this might happen because they are deprecated and thus exist, while the docs only check for wrong links
Yep, but they have doc(hidden)...
Also depending on your lints you also won't receive errors for things that are clearly types but aren't formatted as links, which then causes no error either
Hmmm, though oddly enough here it uses a deprecated alias and it just shows wrong in formatted text too https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/action/events/struct.Start.html
Like what is that [Fired] thing, that's clearly supposed to be a link 
Yeah, it's cursed π
Opened a fix: https://github.com/simgine/bevy_enhanced_input/pull/245
I'll draft a patch release after the merge
whoops looks like when I renamed them my IDE didn't feel like following suit for the docs 
Mine also doesn't rename docs. But I think it should be implemented on the rust-analyzer side to work π
Drafted.
Just wanna mention that BEI's code is a lovely well to draw from for an API I'm drafting up in an AI behavior crate π #game-ai message
there's so much high quality code I can adapt 
Is there a difference between these two?
bindings![A, B, C]
bindings![(A, B, C)]
Because it seems to me like the API is going through a few hoops to support the latter, even though it seems to me as if that's semantically wrong?
Since they all get converted into Binding, and you can't have a single entity with multiple Binding components
Or did I get something wrong?
I would love to have the tuple one be an easy way to bind a chord. To me it seems like it is semantically wrong if it currently works π€
Looks cool!
Yes, first is 3 entities, the second is a single entity with 3 components. Just like with children!.
The only special sauce is that I magically convert first argument into a Binding. Otherwise it would be annoying to type things like Binding::from(KeyCode::Space).
I hope when BSN comes we'll be able to drop this and actions! macro π
Ooooh so thatβs what that code does
But is there a semantic difference for BEI?
Yes, this is 3 bindings with 1 component each:
bindings![A, B, C]
This is a single binding with 3 components:
bindings![(A, B, C)]
But what is the actual difference in how BEI behaves?
You have 1 bindings vs 3 bindings. You can't attach multiple Binding to a single entity.
So if A, B, and C are all Binding, second example will simply panic.
Oh, so the second one is for when you want to attach metadata to the binding, like a Name?
Yes. Also modifiers, conditions, etc.
They work with bindings too
Ooooooooooh
Okay, now it all makes sense
And a user just needs to make sure the first component is the binding
Action-level modifiers and conditions just applied to all bindings.
Binding-level ones applied to specific bindings.
For example, you may want to apply sensetivity to a binding.
That makes sense, thanks for the explanation π
It's a bit magic, but I decided it's worth it over Binding::from.
Well if itβs good enough for you, it shall be good enough for me π
Again I cannot stress enough how incredibly helpful the BEI source code is for me right now haha
Thanks, I really glad people like this design π
Looking at ContextInstance right now
I love the trick with the function pointers
Am I understanding it correctly that you're using function pointers to functions derives from generic functions so that the struct itself is not generic?
that's brilliant
Yep!
Thank you!
I learned it from @cursive gorge, she suggested this approach for ser/de customization in bevy_replicon π
I just noticed that IntoBindingBundle can have an on_unimplemented diagnostic
that makes it more clear why something is not working π
I'll PR it, sec
@sharp warren this text fine?
{Self}is not a valid binding bundle. The first element must be aBinding.
Or more wordy?
Looks great!
Maybe "must be convertible into a Binding".
I need the movement input in another action (that happens to be on another context on the same entity), do we have an easy way to access that or order it so that I can read where it wrote its data?
If you need data from another action, you can query for it.
How exactly would I query it? Do I iterate trough the related actions on the context entity?
If your action is unique, you can use Single.
Otherwise yes, just query query for related actions and use iter_many.
They are currently unique, but I'm writing my code on the assumption I'll want to add split screen support later (which I am planning to do)
iter_many seems to work, nice
@sharp warren do you have experience with the foo!(Bar[ ... ]) syntax confusing rustfmt?
e.g. this is not indenting for me
tasks!(Sequence[
op("a" ),
tasks!(Sequence[op("b"), op("c")]),
]),
Yep :(
Not sure how to solve this.
In my case, I could replace it with
Sequence,
tasks![
op("a"),
Sequence,
tasks![op("b"), op("c")],
],
But I kinda like the fact that right now tasks! ensures that you specified either Sequence, Select, or custom
@sharp warren I'm done with the AI library and now moved on to finally doing a solid kinematic character controller
I'd like to hardcode it to work with BEI out of the box as nicely as possible
Seems like the best way to do that is to do all input accumulation internally (so the user doesn't get to see that nasty boilerplate), and expose the... idk the precise term, the structs that have #[action_output(Vec2)]
then userland code can just do
pub(super) fn plugin(app: &mut App) {
app.add_input_context::<PlayerInput>();
}
#[derive(Component, Default)]
#[component(on_add = PlayerInput::on_add)]
pub(crate) struct PlayerInput;
impl PlayerInput {
fn on_add(mut world: DeferredWorld, ctx: HookContext) {
world
.commands()
.entity(ctx.entity)
.insert(actions!(PlayerInput[
(
Action::<Movement>::new(),
DeadZone::default(),
SmoothNudge::default(),
Bindings::spawn((
Cardinal::wasd_keys(),
Axial::left_stick()
))
),
(
Action::<Jump>::new(),
bindings![KeyCode::Space, GamepadButton::South],
)
]));
}
}
where Movement and Jump are exported by the character controller
first question: does that seem reasonable?
second question: what about NPCs?
It would be neat if NPCs could use the same character controller as the player, but how would such a BEI-native library deal with that? Is it good design to tell the users to mock the inputs to the NPCs?
Or I guess I can just tell users to directly manipulate the accumulated input component that is handled behind the scenes anyways:
/// Input accumulated since the last fixed update loop. Is cleared after every fixed update loop.
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component)]
pub struct AccumulatedInput {
// The last non-zero move that was input since the last fixed update loop
last_movement: Option<Vec2>,
// Whether any frame since the last fixed update loop input a jump
jumped: bool,
}
not sure what the cleanest design for NPC inputs here is
Yes, that how I actually imagined other libraries use it!
I think so, yeah. The mocking API is quite simple.
okay that's a relief!
That means I need to do very little on the library side π
I wonder if there's a smarter way to accumulate the inputs than
fn apply_movement(
movement: On<Fire<Movement>>,
mut accumulated_inputs: Query<&mut AccumulatedInput>,
) {
if let Ok(mut accumulated_inputs) = accumulated_inputs.get_mut(movement.context) {
accumulated_inputs.last_movement = Some(movement.value);
}
}
fn apply_jump(jump: On<Fire<Jump>>, mut accumulated_inputs: Query<&mut AccumulatedInput>) {
if let Ok(mut accumulated_inputs) = accumulated_inputs.get_mut(jump.context) {
accumulated_inputs.jumped = true;
}
}
fn clear_accumulated_input(mut accumulated_inputs: Query<&mut AccumulatedInput>) {
for mut accumulated_input in &mut accumulated_inputs {
*accumulated_input = default();
}
}
In another project I used the pull-based API instead
But in there I just hardcoded it to PreUpdate
But that wouldn't work in the general case, where a user may be running BEI in any schedule
so I resorted to having these trivial observers
Yes, this will work for any user schedule as you get inputs immediately.
Yeah I was just wondering if there's a less... repetitious way of doing it
Since if I allow e.g. 10 inputs, I will end up with 10 observers that look the same
guess I can do a macro 
Maybe use generics? π€
wouldn't allow me to set accumulated_inputs.last_movement specifically
But you still need to assign which struct corresponds to each field
exactly haha
what's that 
at least this is not an issue for the end-user code
It's a HashMap with TypeId and noop hasher.
since from their perspective this design Just Works if they use BEI "normally"
Because TypeId is already a hash
Oh so you mean I could have a hash from TypeId to... Vec3?
A specialized hashmap type with Key of TypeId Iteration order only depends on the order of insertions and deletions.
thx, I definitely could have used this in the past had I known it haha
You have a bunch of action-structs and you need to map it to the fields on your accumulation struct, right?
So with TypeIdMap you can have keys that directly represented by types.
NB this is one of the things that annoys me about Tnua. Using it with BEI the naive way will give you subtly different results depending on your framerate because it does not factor in input accumulation.
But if it's only a few, I'd just repeat the code. Sometimes repetition is okay.
yeah exactly, but I'd not sure how that would look in-code
yeah agreed
especially since the code in question is like 10 LOC per repetition
A generic function over the action that does the insertion to the map based on the action type. And values stored as ActionValue.
throwback to when I had a bug report that jumping on low-end PCs caused your jumps to be twice as high than on a fast PC lol
Ooooooooh I forgot about ActionValue
gotcha
I'll stick with your suggestion of repeating the code, but I'll remember this for future reference. Thanks!
Bindings::spawn(
Axial::<Binding, Binding> {
x: GamepadButton::LeftThumb.into(),
y: GamepadButton::RightThumb.into(),
},
)
```This one seems rather awkward π€
Could you PR a helper, similar to Axial::left_stick?
I guess a ::new() could work with Into<Binding> if that's the intended behavior here? π€
Yeah, for Axial it makes sense.
I usually provided direct helpers because the number of arguments could be large.
But it might worth reducing the amount of helpers in favor of new
Is Axial even the right thing here, I'm trying to map it to a f32, just feels a bit wrong π€
In Bevy sticks also f32. They are split into axes.
In this case I had a 0 or 1 button, and another 0 or 1 button and I need -1 to 1
Ah, there is Bidirectional for this
Ah, if that's what you want, then yes π
My camera control actions are truly cursed 
(
Action::<Rotate>::new(),
Scale::new(Vec3::new(0.0035, 0.002, 1.)),
Bindings::spawn_one(Binding::mouse_motion()),
),
(
Action::<Rotate>::new(),
DeadZone{kind: DeadZoneKind::Axial, lower_threshold: 0.2, upper_threshold: 1.},
Scale::new(Vec3::new(0.032, -0.012, 1.)),
DeltaScale,
Bindings::spawn(Axial::right_stick()),
),
(
Action::<Zoom>::new(),
Scale::new(Vec3::new(0.3, 0.3, 1.)),
Bindings::spawn((
Spawn((Binding::mouse_wheel(), SwizzleAxis::YXZ)),
Bidirectional::<Binding, Binding> {
positive: GamepadButton::LeftThumb.into(),
negative: GamepadButton::RightThumb.into(),
},
))
),
But unlike the rest of my game they have some simple observers like:
fn zoom_camera(trigger: On<Fire<Zoom>>, mut control: Query<&mut CameraDistance>) -> Result {
let mut zoom = control.get_mut(trigger.context)?;
**zoom = (**zoom - trigger.value).clamp(1., 15.);
Ok(())
}
Looks alright, but I definitely need to tweak helpers π€
Add new for convenience and drop most helpers, keeping only the common ones.
Before:
Bidirectional::<Binding, Binding> {
positive: GamepadButton::LeftThumb.into(),
negative: G...
[main bf0395d] Switch from leafwing-input-manager to bevy_enhanced_input
43 files changed, 461 insertions(+), 564 deletions(-)
```The extra deletions are somewhat misleading, but overall the code is a lot nicer now π₯³
does anyone has an idea on how
app
.add_plugins(EnhancedInputPlugin)
.add_input_context::<Player>()
.finish()
;
can hard freezee my app (can't even kill with the terminal I have to kill my terminal)
Should I make a bugreport on that?
the engine is absolutely unresponsive when it hits the finish()
bevy = { version = "0.17.2" andbevy_enhanced_input = "0.19.3"
No idea, but have you tried running examples?
I'll do that later and file a bug report if the bug persist
I'm using an example tho, so that sort of count as that
I wonder if it's reproducible within the repo
you want me to download the repo and try from there, copy
okay examples works, so the issue was my code somehow
I had copied from https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/#putting-it-all-together
A powerful observer-based input manager for Bevy.
believing that was to be called example
use bevy::prelude::*;
use bevy_enhanced_input::prelude::*;
#[derive(Component)]
struct Player;
#[derive(InputAction)]
#[action_output(bool)]
struct Jump;
#[derive(InputAction)]
#[action_output(bool)]
struct Fire;
pub struct ControlTestPlugin;
impl Plugin for ControlTestPlugin{
fn build(&self, app: &mut App) {
app.add_plugins(EnhancedInputPlugin)
.add_input_context::<Player>()
.finish()
;
app.world_mut().spawn((
Player,
actions!(Player[
(
Action::<Jump>::new(),
bindings![KeyCode::Space, GamepadButton::South],
),
(
Action::<Fire>::new(),
bindings![MouseButton::Left, GamepadButton::RightTrigger2],
),
])
));
}
giving me this code
but that is flawed somehow and causes the issue described earlier
the main only has:
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(ControlTestPlugin)
.run();
}```
reducing the BEI to
pub struct ControlTestPlugin;
impl Plugin for ControlTestPlugin{
fn build(&self, app: &mut App) {
app.add_plugins(EnhancedInputPlugin)
.finish()
;
}
}```
still causes the issue
ah probably because of finish being used not in the main
I guess you don't use finish?
removing finishes now causes other issues, what's the most minimal functionnal example?
The rust community truly hates examples that are sufficiently small to be visibly in full screen, making them totally accessible for someone that just landed in
Ah, of course, you shouldn't call finish
Calling run already does finish.
Drafted a new release with this change.
You can now write this a little bit nicer π
Ping @thick kiln to update Lightyear. Should be just a version bump.
@sharp warren I've got a little problem with the setup we discussed a while ago
Here:
fn apply_movement(
movement: On<Fire<Movement>>,
mut accumulated_inputs: Query<&mut AccumulatedInput>,
) {
if let Ok(mut accumulated_inputs) = accumulated_inputs.get_mut(movement.context) {
accumulated_inputs.last_movement = Some(movement.value);
}
}
fn apply_jump(jump: On<Fire<Jump>>, mut accumulated_inputs: Query<&mut AccumulatedInput>) {
if let Ok(mut accumulated_inputs) = accumulated_inputs.get_mut(jump.context) {
accumulated_inputs.jumped = true;
}
}
fn apply_crouch(crouch: On<Fire<Crouch>>, mut accumulated_inputs: Query<&mut AccumulatedInput>) {
if let Ok(mut accumulated_inputs) = accumulated_inputs.get_mut(crouch.context) {
accumulated_inputs.crouched = true;
}
}
fn clear_accumulated_input(mut accumulated_inputs: Query<&mut AccumulatedInput>) {
for mut accumulated_input in &mut accumulated_inputs {
*accumulated_input = default();
}
}
if this is my library code, the user wouldn't be able to change this to e.g. only jump when Jump has been released 
right?
The Fired depends on the condition, so if user can attach Release, it will jump on release.
Oooooooh π
thanks!
do we also have some kind of builtin toggle?
What do you mean?
some way of saying "when I press CTRL it will fire the crouch action every frame until I press CTRL again"
Asking since usually I handle that in the observer that observes the Fire, but since this is now in the library code, that would need to be configured by the user
Actually, no π€
But it sounds like a reasonable thing to add.
In Unreal you don't really need it because it's all nodes and there is a built-in node. So you just use it before you connect logic to the input.
I'm deep in the KCC rabbit hole, otherwise I would volunteer to PR it
But it makes sense for Bevy
yeah makes sense
I'm a bit busy with bevy_replicon too... Let's just wait for a brave soul who needs a toggle π It shouldn't be hard to implement.
yeah sooner or later that brave soul will be me haha
What I like about conditions is that users can write them by simply implementing a trait.
So even before the upstreaming, people can try it in their codebase without any patching and later upstream if they want.
You could make an issue describing it so the next pour soul that comes along knows it can be implemented and knows what to do?
That would actually be really neat as long as it's easy for code to reset the toggle, eg you toggle sprinting but it stops if you stop moving (not the desired game in every game ofc, and for example with crouching you're gonna want to keep crouching even if you stop moving)
Good point!
With the component-based design it should be easy. Just query and flip the toggle.
Having the ability to spawn bindings like that without having to change actual handling of the actions would be great though
Would greatly simplify adding important accessability features like toggle sprint/crouch/etc
You mean spawning some actions/bindings later on? It's supported
Ah, you mean having the same logic that processes the action in observer/system with and without toggle bindings?
I think this should already work the same since the concept of press and release is abstracted. Like in the example above, user slaps Release modifier and it still works since the reacting logic only cares about Fired.
Yea, just in this case you can remove the regular binding, and spawn a toggle binding
(Or just add/remove the component)
Hi new user of this crate. It's pretty exciting, so far quick to setup. But I am having some trouble with some action binding and specifically my left stick on my PS5 dual sense controller (I have tested it work fully)
(
Action::<crate::controls::Move>::new(),
DeadZone{kind: DeadZoneKind::Axial, lower_threshold: 0.2, upper_threshold: 1.},
Scale::new(Vec3::new(1., 1., 1.)),
Bindings::spawn(Axial::right_stick()),
),
(
Action::<crate::controls::Move>::new(),
DeadZone{kind: DeadZoneKind::Axial, lower_threshold: 0.2, upper_threshold: 1.},
Scale::new(Vec3::new(1., 1., 1.)),
Bindings::spawn(Axial::left_stick()), // Bidirectional::new(KeyCode::ArrowLeft, KeyCode::ArrowRight),)
),
here I have defined both left and right sticks to the same action (for debug) but the left stick never writes a value to the X axis. The right will do this correctly though. I could very easily be doing something incorrectly but the right working left not working is a pretty strange π§©
Any ideas what the issue might be?
Strange, your setup looks correct.
Try running the flycam example in the repo, does it work it for you correctly?
Which one is the flycam example?
all_conditions
basic_action_management
character_controller
context_layering
context_switch
hotbar
keybinding_menu
local_multiplayer
It's basic_action_management
@sharp warren yep this works as expected. So does the character_controller example.
I have 2 contexts like the docs [on foot, in car] the "in car" context only uses
(
Action::<controls::Steer>::new(),
// Bindings::spawn(Axial::left_stick()),
bindings![
GamepadAxis::LeftStickX,
],
),
could this be related? (obviously this is the intention of contexts) I have attempted to test using the left full stick also (did not change anything)
@sharp warren just to make sure I'm correct, this is what my InputAction should look like?
#[derive(Debug, InputAction)]
#[action_output(Vec2)]
pub struct Move;
I think it might be because you use the same action twice
I never tried something like that.
Just put both sticks to the Bindings::spawn
Nailed it! Thanks @sharp warren that was the issue. I took the car out and the left stick works as expected.
So in my case I have a [steer] car (X axis only) and [movement] player InputAction which I bind on each entity. This #1297361733886677036 message code was simply testing the sticks. I really only use the Axial::left_stick() part.
Sorry but I'm not sure what you mean by "Just put both sticks to the Bindings::spawn"
If you don't need both sticks for the movement, just remove the extra action.
So with having 2 different contexts [in car, on foot] I shouldn't have actions bound to both?
this is the car when spawned
LinearVelocity::default(),
AngularVelocity::default(),
controls::DrivingContext,
actions!(
controls::DrivingContext[
(
Action::<controls::Throttle>::new(),
bindings![
GamepadButton::RightTrigger2,
],
),
(
Action::<controls::ThrottleReverse>::new(),
bindings![
GamepadButton::LeftTrigger2,
],
),
(
Action::<controls::Steer>::new(),
// Bindings::spawn(Axial::left_stick()),
bindings![
GamepadAxis::LeftStickX,
],
),
(
Action::<controls::Interact>::new(),
bindings![KeyCode::Space, GamepadButton::South],
),
]
),
and here is the player when spawned
Transform::from_translation(spawn_pos),
RigidBody::Dynamic,
Collider::capsule(0.4, 0.8),
LockedAxes::ROTATION_LOCKED, // Keep upright
Player,
Health::default(),
crate::controls::OnFootContext,
actions!(
crate::controls::OnFootContext[
(
Action::<crate::controls::Move>::new(),
DeadZone{kind: DeadZoneKind::Axial, lower_threshold: 0.2, upper_threshold: 1.},
Scale::new(Vec3::new(1., 1., 1.)),
Bindings::spawn(Axial::left_stick()),
),
// removed debug Axial::right_stick() binding
(
Action::<crate::controls::Interact>::new(),
bindings![KeyCode::Space, GamepadButton::South],
),
]
),
No, you just can't have the same action in the same context twice.
Ok understand. Thanks π that was only for debug. If I remove (which I have) the duplicate action binding nothing changes for the player [on foot] there is only a single axis of movement.
If I do not spawn the car at all, which binds the left stick X axis when in that context the player [on foot] moves correctly.
As, so the problem persists?
it appears to me that the binding for the left stick X axis is stuck on the car and the player cannot use it?
Ah, but in your code you LeftStickX, no?
yep for the car context only.
#[derive(Debug, InputAction)]
#[action_output(f32)]
pub struct Steer;
is bound as the action.
So you have 2 contexts active at the same time?
It looks like it. I have only used .add_input_context in the build and I use a state to switch between [on foot] and [in car] ... but those are bevy states, I'm not sure how I switch a context off.
So it looking at https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/context/struct.ContextActivity.html I should be inserting ContextActivity::INACTIVE when the state changes for the car (the player despawns) Or calling toggled on the context component by the looks of it.
Enables or disables all action updates from inputs and mocks for context C.
I am trying to figure out how to create a chord for pressing the jump button while holding down β¬οΈ on either the keyboard, dpad, or gamepad left stick. Is there a way I can use my existing Move command (Vec2) as the chord and check if the y value is less than one?
Or if I create a new action, I don't know how to specifically set the gamepad y axis negative to fire it. I know how to set the down arrow and down on the dpad.
This depends on your use case. If you want both to be active at the same time, you need to configure which context evaluates first via ContextPriority.
If you want to toggle between them, you can use ContextActivity.
I highly suggest to read the quick start guide in the docs if you haven't yet.
No, you will need a separate action for it.
Alternatively, you can create a custom Chord run condition based on the current one.
I'm also open to adjust our current Chord to add a configuration , but I can't imagine how we could express something like this nicely π
I have a much better understanding now and I'm using ContextActivity ACTIVE/INACTIVE , I will read the docs some more and they should make more sense. Thank you very much for the help @sharp warren
What is a custom Chord run condition? Is there an example?
@sharp warren just wanted to say that BEI is allowing me to have a lovely tiny API surface for my KCC:
use bevy::prelude::*;
use bevy_enhanced_input::prelude::*;
use bevy_ahoy::prelude::*;
#[derive(Component)]
struct PlayerInput;
fn spawn_player(mut commands: Commands) {
// Spawn the player entity
let player = commands
.spawn((
// The character controller configuration
CharacterController::default(),
Transform::from_xyz(0.0, 20.0, 0.0),
// Configure inputs
PlayerInput,
actions!(PlayerInput[
(
Action::<Movement>::new(),
DeadZone::default(),
Bindings::spawn((
Cardinal::wasd_keys(),
Axial::left_stick()
))
),
(
Action::<Jump>::new(),
bindings![KeyCode::Space, GamepadButton::South],
),
(
Action::<Crouch>::new(),
bindings![KeyCode::ControlLeft, GamepadButton::LeftTrigger],
),
(
Action::<RotateCamera>::new(),
Scale::splat(0.04),
Bindings::spawn((
Spawn(Binding::mouse_motion()),
Axial::right_stick()
))
),
]),
))
.id();
// Spawn the camera
commands.spawn((
Camera3d::default(),
// Enable the optional builtin camera controller
CharacterControllerCameraOf(player),
));
}
That's already it. No glue, no managing inputs, no fussing around with schedules, nothing
I simply export Movement, Jump, Crouch, and RotateCamera from the library and the user sets up a binding. Done.
Great job with the API design of BEI, this is really powerful π
I.e. you can copy the existing Chord implementation and edit it to your liking in your crate without patching.
Just don't forget to register it via app.add_run_condition<YourCustomChord>().
Awesome, I love it π
Ah, I forgot to asnwer about separate action.
Just assign the axis and clamp it only to negative:
https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/modifier/clamp/struct.Clamp.html
Restricts input to a certain interval independently along each axis.
For your use case, I'd probably do this ^
Making a custom condition would be overkill.
We could also extend Chord to assign a desired value that triggers the chord, but it's a bit ugly π€
I think a separate action fits better.
if i wanted a wasd-keys-like Cardinal input but with key-overriding behavior (e.g. im holding A going left, and then press down D without letting go A, it should override A and start going right. If i then let go D it should start going left again. if i hold A, press D, then let go A and press it down again, it should start going left again) how would i go about doing that?
Defines how ActionValue is calculated when multiple inputs are evaluated with the same most significant ActionState (excluding ActionState::None).
thanks, this half works, it only overrides in one direction
if i hold D and then press A, it doesnt change direction
want it to resolve ties by taking the most recent input direction per axis
maybe a third accumulation is needed
Ah, right π€
Yeah, we probably need an additional strategy. Or just a boolean inside MaxAbs
we could also make it always resolve this way in MaxAbs if the absolute values are the same
all my directions are unit length
i think this resolution strategy would be preferred if the absolute values are the same
I.e. pick the last one?
the newest one
yeah
would this just be making this < a <=
Accumulation::MaxAbs => {
let mut value = self.value.as_axis3d().to_array();
let other_value = other.value.as_axis3d().to_array();
for (axis, other_axis) in value.iter_mut().zip(other_value) {
if axis.abs() < other_axis.abs() {
*axis = other_axis;
}
}
value.into()
}
testing rn
nope
that just inverts the direction that dominates
okay so these things arent ordered by recency
hmmm
how do we recovery recency?
Yep, we just evaluate actions in order they defined.
What is your use case, btw? π€
character control
For things like movement accumulation usually common
Yeah, I mean what kind of game?
Do you think accumulation wouldn't work for it?
fps-y
well it would but i want this specific feel to it
cus itd be snappier
if the key you press always immediately does the direction then it feels better
rather than waiting for the other key to be unpressed or having a couple no movement frames inbetween
It's quite unusual. In all games I've played it's accumulation π
Both modern games (like Marvel Rivals) and old (like Quake 2).
But you can still get this behavior by adding a custom input modifier.
Wait, not entirely sure if it's possible via a modifier or custom state tracking.
You will need to split your movement keys π€
Yes, I think using different actions for each direction is the only option.
Yeah... I'm also open extending the crate, but I'm not entirely sure how something like this can be integrated
But I'd suggest to try different directions and see how it feels.
do you support key chord bindings? stuff like how vs code lets you change document highlighting by pressing ctrl + k and then m in quick succession
Yep, see the Chord condition
Yeah, you can create a chord from 2 other chords
Wait, no, when you want a sequence, you need Combo
Yes, use Clamp
thx, let me try
(
Action::<Jump>::new(),
Clamp::pos(),
bindings![Binding::mouse_wheel()]
),
this seems so still trigger on both up and down 
Can you enable logging and see how the clamp transforms the input?
sure, by regular RUST_LOG?
2025-11-29T12:24:54.517506Z DEBUG bevy_enhanced_input::action::fns: triggering `STARTED` for `Jump` (`252v0`) for context `241v0`
2025-11-29T12:24:54.517525Z DEBUG bevy_enhanced_input::action::fns: triggering `FIRED` for `Jump` (`252v0`) for context `241v0`
2025-11-29T12:24:54.523512Z DEBUG bevy_enhanced_input::action::fns: triggering `COMPLETED` for `Jump` (`252v0`) for context `241v0`
2025-11-29T12:24:55.984066Z DEBUG bevy_enhanced_input::action::fns: triggering `STARTED` for `Jump` (`252v0`) for context `241v0`
2025-11-29T12:24:55.984081Z DEBUG bevy_enhanced_input::action::fns: triggering `FIRED` for `Jump` (`252v0`) for context `241v0`
2025-11-29T12:24:55.990436Z DEBUG bevy_enhanced_input::action::fns: triggering `COMPLETED` for `Jump` (`252v0`) for context `241v0`
I assume you meant to debug print it manually, as this doesn't show the transform
2025-11-29T12:27:32.308240Z INFO bevy_ahoy::input: jump=On { event: Fired { value: true, state: Fired, fired_secs: 0.0, elapsed_secs: 0.0 }, trigger: EntityTrigger, _marker: PhantomData<()> }
2025-11-29T12:27:33.695994Z INFO bevy_ahoy::input: jump=On { event: Fired { value: true, state: Fired, fired_secs: 0.0, elapsed_secs: 0.0 }, trigger: EntityTrigger, _marker: PhantomData<()> }
well, not much to transform, given that it's a bool output
I see, that's probably the issue
#[action_output(Vec2)] fixes this
#[action_output(f32)] does not FWIW
No, no, I meant RUST_LOG, when you enable trace, it shows how modifiers affect input. It's quite verbose, though :)
ah I see
sec
I'll revert to bool
Yeah, I'd expect it to be a bool.
oh this is almost impossible to do :/
it seems like it prints stuff every frame
Oh wait, I can panic! on the input
Yeah, just redirect into a file
Could work too π€
Ah, I see. The scroll outputs Y value.
Transform it into X value first
I.e. swizzle it
Also looks like you have 2 jumps?
(
Action::<Jump>::new(),
Clamp::pos(),
SwizzleAxis::YXZ,
bindings![Binding::mouse_wheel()]
),
like so?
No, on the input
yeah I wasn't sure how to bind it other than this:
(
Action::<Jump>::new(),
Press::default(),
bindings![KeyCode::Space, GamepadButton::South],
),
(
Action::<Jump>::new(),
Clamp::pos(),
bindings![Binding::mouse_wheel()]
),
like this?
(
Action::<Jump>::new(),
Clamp::pos(),
bindings![(Binding::mouse_wheel(), SwizzleAxis::YXZ)]
),
Yep!
same result :/
Ah, you need either use f32 or move Clamp to the binding as well
Your action is bool. When the binding gets evaluated, it converts into the action value. It's too late to apply Clamp at this point.
yesssss
(
Action::<Jump>::new(),
Press::default(),
bindings![
KeyCode::Space,
GamepadButton::South,
(Binding::mouse_wheel(), SwizzleAxis::YXZ, Clamp::pos()),
],
),
this here does everything I need π
Yeah, that's what I'd do π
So cool that the API is able to express that π
Do you have some advice on how to provide API for default bindings?
without it being too magical
e.g. required components would maybe work, but that would not allow users to manage their input actions however they want
I could provide a function like default_input_actions, but that would that just use a default input context that is already preregistered?
sounds a bit magic
but having the user provide their own input context in a generic could also be weird
One of the options is to provide a simple resource with bindings.
But this might limit the customization because all modifiers and conditions will be hardcoded.
So it depends on how opinionated your controller will be
hi @inner sky, or whomever. this is a fairly basic question and my intent is to understand BEI better. in your bevy_ahoy crate, the right axis for a controller is bound to camera controls. in the minimal example, using a controller (ive tried a few controllers but curerntly using a DS4) to look around results in reversed up/down pitching. the BEI example for character control appends ".with(Negate::x())" to the right stick bind. in that example, and when modifying the bind in your minimal setup for ahoy with a negate, this results with reversed left/right, yaw and a proper up/down. to me this implies that both axes are being reversed for some reason, instead of just one.
is this intentional? what am i not understanding about this? my goal is to bind the controls so that pushing upwards on the analog stick looks up, and down looks down, etc
oh I should actually test it on controller haha
something else i should mention is that your splat scaling works fine for mouse but is way too slow for the controller stick, so i suppose youd do something like .with(splat(.4)) on the right stick
noted, thanks
I'll run it later with a controller and debug the things you mention π
and thank you very much for the crate. having an example like this to work and learn from is much needed. i was struggling a lot trying to understand physics/movement/system ordering and ahoy has so far been invaluable in filling in blank spots for me
I highly highly recommend reading https://github.com/myria666/qMovementDoc in that case!
it will help you much more than reading through the source code, I believe
yes, ive been reading this. great resource
it is the default in most FPS games but all the pro players usually change this using configs and scripts. look at the amount of tutorials for CS2 for example.
@frozen spear in case you get this working, I'd be interested in making it the default for Ahoy π
that would be cool. yeah its just like, better movement
i would like BEI to support it out of the box
i think the way to get BEI to support this is to have bind processing be ordered not by declaration order but by pressing order
then it gets pretty trivial. idk if that breaks anything though, @sharp warren would know better
Do you know any game that implements this behavior?
Could you also link a script or config for CS2? It's the first time I hear about it π€
Shouldn't break anything, but it's not trivial to implement
I might understand it wrong but changing the order in which actions are executed can be/is breaking no?
Rotate + move != move + rotate, declaration order allows this to be deterministic
it wouldnt change the order in which the input is consumed
just the order in which its processed internal
BEI has no concept of rotation or moving, only axes afaik
@sharp warren i thought a bit more about it, and i think whats actually desired here is timestamps on the input somehow
cus that can be used to combine it unambiguously
and also be used for other things
It would be great, but Bevy doesn't provide this information.
like knowing exactly when within a frame a button was pressed
i think that until we have real timestamps (idk when this happens) it makes sense to have fake internal timestamps of some kind no?
like, we could do something as stupid as just reading system time when we see a key press and saving it next to it, with the expectation to switch to real timestamps eventually
for wasd ordering that would be enough
It's something that needs to be done on the Bevy side. Because inside events we don't have this information.
@frozen spear have you tried manually making this logic by splitting movement into X and Y axes and adding custom logic to implement the desired behavior?
Why not?
cus its more complicated than it should be, and will make gamepad support painful
also im doing other things lol
ill probably end up doing that if theres no other way and i really need it
im not the only one who wants this though
Feel free to ignore the advice, but I'd suggest to quickly hack it together and see how it feels.
Because there might be a good reason why other games don't implement input like that.
i already know how it feels because ive used controllers that behave like this
You mean actual hardware or software implementation of input controller for games?
software
although there are keyboards that do this
theres keyboards specifically designed for this, which cancel out A when D is pressed and vice versa, same for W and S
Could you point me to it? I'm curious to see.
BTW, this solution is not that hacky. In Bevy sticks also split by axes.
its called auto counter strafe, heres some links from a google search
https://github.com/LovelyNacl/Auto-Hotkey/blob/master/CounterStrafe.ahk
https://www.reddit.com/r/GlobalOffensive/comments/173ky0t/auto_counter_strafe_fast_stop_quick_stop_auto/
https://github.com/danielkrupinski/Osiris/issues/928
https://gist.github.com/CoolOppo/9984632
Ah, you meant via scripts. Very interesting, thank you a lot!
(I might try it myself)
i have some C# code that does this that i wrote ages ago somewhere for my game
idk where it is now though
Razer called this feature snap tap, and it has been very controversial in cs2, afaik it's mostly banned in competitive/pro play these days
yeah
i think whether its fair or not doesnt matter if you're a gamedev putting it in base game though
thats just a feature then and everyone has it. if anything it levels the playing field
Yeah I agree, it doesn't have to be unfair, but in CS2 specifically it's seen as a kind of cheat/aid because counter strafing is a core part of the game. If it's part of the game then it's fine.
and yeah the hardware impls of this go to even more ridiculous lengths, like tuning the key depth activation threshold to make it even more immediately responsive
Would Time::elapsed() not work as a best guess for now?
But how can we get this information from the event?
Canβt you query Res<Time> when processing it?
(With the obvious caveat that this is discretized to the frame rate)
But this will be the information when an action is processed.
I think we need the time the key was pressed.
Otherwise it's just the evaluation order
Yeah, but if it was not pressed in the exact same frame, it would already work, no?
To be clear, I mean reading the elapsed time in the BEI systems that run in PreUpdate by default
Looks like it doesn't work in CS2 anymore but there are configs for other games like TF2 or L4D2. It's called a null movement config. Example: https://github.com/ChadyG/TF2-configs/blob/master/null_movement.cfg
Ah, I get it now. It's actually already there:
https://docs.rs/bevy_enhanced_input/latest/bevy_enhanced_input/action/struct.ActionTime.html
This means we could implement this via modifier.
Timing information for Action<C>.
Thanks!
oooooh yay so its possible?
we can make it pick the newest by using the elapsed time in an action modifier?
Thinking about this more, the elapsed timer represents the action time. So it won't reset with the direction change...
So we might need to add it per-input.
We have to rewrite the winit integration first at least iirc
@sharp warren I have a biiiiiiig actions! block right now, and would like to introduce a chord. The examples I could find for chords don't use the actions! macro, I assume due to syntactic limitations. But I would be very sad if I had to replace my entire actions! block haha.
How do I add an action with a chord after the actions! block? I suppose something like with_related::<Action>?
You mean something like this? (i.e. ActionOf)
let id = commands .spawn((Action::<T>::new(), slot_modifiers(ability), bindings![key, gamepad_button])).id(); commands.entity(player_entity).add_one_related::<ActionOf<Player>>(id);
You can also insert ActionOf(entity) directly. Basically, anything you would do with Parent/Children.
Thx!
New question: what would be your advice for how to record input?
I would like to record the inputs I execute in a certain time frame (eg start recording when pressing F3, stop when pressing F3 again) and then play it back as a unit test
Or I guess end-to-end test more like
Is there some prior art? Or do I basically just write the input timestamp into a text file when the observer for an action is triggered?
And then mock those inputs in a test run, dividing the timestamp by some speedup factor
I think having a crate for this would be really cool.
I didn't include this into BEI because it might be a bit opinionated.
The way I'd do it is to just run a system after the input processing and record the state and value if it's Changed for each action. So I'd encode it in a form of "Use this value of the action for X frames".
Oooh thatβs clever!
I'll probably do that crate over the weekend since I kinda need it
If you want, I can donate it to simgine after π
I think it's better to have the authority distributed. So everyone maintains what they use π Reduces the bus factor and such.
But having the mention in the readme might be useful π
Maybe it could work via the events StartRecording and EndRecording and write everything into an Asset
Makes sense
(Events are triggered on a specific entity holding actions)
Yep, sounds convenient.
Could also add IgnoreRecording markers to actions in case someone needs that
Then in my KCC, I can conveniently expose that as a StartRecording and StopRecording action instead of an event
Since the whole API is action based
I like the described API a lot!
Btw I've had even more people asking "can you make the input for this movement support this weird thing" and my answer is still always "yes, itβs BEI, you can bind or mock the action however you want"
And I implemented input buffering and coyote time downstream since it was really trivial
Well, trivial for me in any case since I input buffer to the next fixed timeframe anyways
So I can just as well buffer that input for say 150 ms on top
BEI is saving me much more work than I thought
@sharp warren hope I'm not pinging you too much π I'm wondering if BEI or Bevy in general has a way to translate keybindings from KeyCode to Key. It seems like BEI's example keybinding menu only shows KeyCodes, but I would like to have the UI display the Key instead
I know you can get the Key once an input has already been made, but what about the preconfigured inputs?
I.e. if I ship a game so that by default it uses the physical W A S D KeyCodes, how would I get my keybinding UI to display that as D A S H, which are the corresponding Keys on my keyboard layout?
It's okay, don't worry π
You mean Binding?
You can store and display bindings in settings too. It's just in games you usually configure gamepad and keyboard separately π€
Yeah in the end I want to display Binding, but not as KeyCode, but as Key
(for keyboard ofc)
for gamepads, idk, I have not thought about that at all π
Ah, I get it. But not sure what to suggest. Maybe we could have a conversion somehow? π€
Yeah I would hope that winit somehow offers us the current keyboard layout so that we can look up stuff
but I wasn't able to find it
not that it doesn't exist, I'm not terribly familiar with the API
Damn, looks like not much we could do
fuck
that's really disappointing for UX :/
maybe there's some other crate I can use downstream to read the keyboard layout and do some weird conversion that way
update: there's : https://github.com/HactarCE/key-names
Platform-aware keyboard key name handling for Rust applications - HactarCE/key-names
Interesting!
I think having something like this in Bevy would be nice π€
Since it's for KeyCode, I feel like it belongs more to bevy_input.
@sharp warren we just ran into something weird. This setup here made Only Tac ever fire, and never Crane
is that intentional?
Don't get me wrong, the setup is wrong anyways, it should be this:
and the second screenshot behaves exactly as expected
but our debugging was a bit hindered by the fact that the code in the first screenshot apparently "consumes" the space input, never triggering Crane
That's correct. You can disable input consumption by changing the ActionSettings.
oh, so if it has no Press or Hold it consumes?
but Press does not consume?
that seems a bit odd 
I'd expect the consumption to happen in both cases π€
Can confirm Press definitely does not consume anything
Ah, I see.
we have like 3 things bound to space haha
First action will trigger on one frame and second action on the second
take a look at this:
Actions consume inputs only if they actually do something.
Press is basically a single press
Yep!
On which entity do I insert the ActionSettings?
On the action entity you want to configure
hmm help me out here
how do I do that when using actions!?
In your screenshot just put it right after Action::<X>::new()
The position doesn't matter
Just looks nicer logically
like so?
hmm that looks like something I personally want everywhere in my app
is there a global setting for disabling consumption?
@frozen spear this is why it behaved the way it did ^
wild
No, we don't have a global default π€
But this might be a good default π€ At least people won't get confused.
for now I just added it to all my actions π
Do you need them to be separate actions? If how the action behaves depends on the situation which can be determined in advance then having them as unique actions in different contexts might work better. If the result of the action depends on things that may occur after the input is done then it might be better to check for that within the action itself and not have separate versions.
To give an example of the former, if you are touching a wall you might be able to create a WallTouching context that would override the Jump action with a Mantle instead. If however, you are allowing the character to Jump into a Mantle if they hit a low enough wall, then that might be better done within the action itself.
The main reason is that people want to configure these independently
e.g. some want mantle to be on a different key
some want to have jumps on release
some don't want to bind cranes at all
(already got all those requests)
so it seems easiest to just toss the actions at the user and let them decide how to bind them
Could you have different contexts for the different play styles?
Of course, it may not be an issue for your game.
I've had problems in a game where they had some things set to not consume inputs while allowing for user defined controls which lead to two different actions which shouldn't have occurred together to happen.
this is a library I'm making, so users can choose to distribute those actions however they want across contexts. I'm only exposing Actions, they have to bind them themselves.
The code I posted above is just the one used in an example π
but good to know, I'll keep it in the back of my mind!
Hello everyone. I'm new to online dialogue, so bear with me.
My goal is to allow an action to deactivate its own context upon being fired. This could be useful for a general SwichContextTo<C> action, which could activate the C context and deactivate the action's current context. (This could be useful for folks who want to transition between mutually exclusive, "state-like" input contexts.)
To do this, the action entity must know which component on its context entity is the correct ContextActivity to deactivate.
Although this can be achieved in the aforementioned use case by adding an additional generic parameter to the action (resulting in SwitchContext<C1, C2>), this would require the user to add a new observer for each (C1, C2) combination. It would be more ergonomic to use SwitchToContext<C>, especially if the observer for this action were added as soon as the context C was registered (e.g. in the InputContextAppExt::add_input_context_to method or a similar custom method).
To make an action entity aware of its corresponding ContextActivity component without introducing extra generics on the action, the action entity could automatically include an ActivityId component that wraps the ContextActivity's ComponentId. This would be as simple as adding the following line in InputContextAppExt::add_input_context_to method (or in a similar, custom extension method):
let _ = self.try_register_required_components_with::<ActionOf<C>, ActivityId>(|| ActivityId(activity_id));
Here comes my problem: I am not sure how to deactivate ContextActivity using its ComponentId. If deactivation were to occur simply removing ContextActivity::<C>, I could use something like:
commands.entity(context).remove_by_id(activity_id);
However, deactivation instead occurs by inserting ContextActivity::<C>::INACTIVE, which limits me to the unsafe EntityCommands::insert_by_id method, and I don't know how I would make this specifically insert the ContextActivity::<C>::INACTIVE variant.
Any help or course correction would be welcome.
The entity could have multiple contexts attached to it. So I don't think you can get away with a single generic.
To clarify, which of these are you saying?
- the action entity can have multiple context components connected to it, or
- the context entity can have multiple context components connected to it
In the case of #1, I assumed that each action entity can have no more than one context (because action entities automatically despawn when a single context entity despawns). If this assumption is wrong, then I unquestionably agree with you.
In the case of #2, context entities can have multiple context components. But since an entity can only have 1 of each component, and since each ComponentId is unique in a given world, wouldn't ContextActivity::<A> and ContextActivity::<B> have different ComponentIds (and therefore, different ActivityId(ComponentId) components for their "children" actions to "inherit")?
It's 2, but now I get it now.
You can workaround it by storing a function pointer during the registration in a component. Once you want to disable the context, you just call this function that does this.
Cool, I'll try it out
I use this trick inside the BEI itself, so you look at the internals for an example
Worked like a charm. The examples/context_switch.rs example was reduced by a whopping ~10 lines
hiya is it possible to handle trackpad scroll?
How is this represented in bevy_input?
PanGesture I think?
If it's gesutres, I didn't include them.
If you're interested in adding them, should be a simple extending of the Binding enum.
Updated to the latest RC, enjoy.
Hi there! I have a use case that I'm not sure how to cover and maybe you could help me out. I have a Hold action that, once fired (and while fired) consumes some resource (picture a stamina bar). I would like to cancel/complete the action once said resource is depleted and the user is still holding down the button so they have to release the button, press and hold again if they want to fire the action again. Any ideas?
I think you can create a custom condition, but I'd suggest to just write your own logic on top of the input.
So a custom BEI condition you mean, cool. And regarding your other suggestion, can you elaborate a bit more? What did you mean with that? Thanks a lot!
I mean you can write your custom reaction logic on top inside observers/systems. I.e. if the bar drains, you pause the logic until the input stops firing and starts to fire again.
I see what you mean, I thought you were referring to some InputAction specific logic that I was unaware of. The problem I'm having with that is the observer that listens to the Fire event can check what you say, but if we add a bar regeneration system into it, whenever the condition gets checked again, the input is still Fired but the bar now has some value other than zero and the cycle continues. So I was looking for a way to potentially tell the input library that the action got released, but not necessarily the key/button associated to it. I hope this makes sense. π€
I just found out BlockBy exists, I wonder if that could help at all... But now I see this is an action that blocks another, I don't think this covers my use case.
You can just have a boolean state somewhere that prevents action from firing until it stops firing first.
But nothing built-in to handle it inside the library comes to mind. Feel free to experiment with this and leave suggestions π
I'm not sure, but you might be able to use some sort of layering of contexts so that upon the first input it adds a context layer if all the conditions are valid that uses that context to add the action and the removal of that context layer is done outside of the action (like when it reaches zero).
Something like an Activate action that adds or activates a Consumption context layer on top with a Consume action (that uses the same binding as Activate) where either releasing the binding, or external to it in a system when the bar is drained, the Consumption context is removed, or possibly inactivated. But the Activate action would need to have its conditions met before it could enter the Consumption context so you could check in that observer if there was regeneration going on or whatever that might prevent the activation.
This sounds like a good alternative, I will give it a go if a simple state based approach doesn't work. Thanks for the ideas!
I ended up using a boolean state wrapped in a Resource, the observer handling the Fire mutates it and then the other systems read this resource as necessary. For now, it works! Thanks a lot for the ideas, I think it was a "writer's block" situation and I needed a different perspective π
I want to remove the ability to move on the diagonals.
Is there an easy built in way to do this or do I have to manually filter the input to only be on the x or y axis at one time?
I'd define separate actions for vertical and horizontal movement
@sharp warren got a weird one for you after the holidays: It looks like Negate::x() negates both X and Y on my controller 
Binding: https://github.com/janhohenheim/bevy_ahoy/blob/main/examples/playground.rs#L235 (Imagine a Negate::x() on the controller binding)
Handling: https://github.com/janhohenheim/bevy_ahoy/blob/main/src/camera.rs#L139
the issue with this is that right now, moving the stick up looks down (like when controlling a airplane). Using Negate::x() makes moving the stick up look up, at the cost of making the stick to left look to the right
meanwhile, Negate::y() (which is what sounds more correct in this case to my mind) doesn't seem to do anything at all for some reason
Unless I'm doing something wrong here
i think i see what the bug is
impl<X, Y, T: Clone> WithBundle<T> for Axial<X, Y> {
type Output = Axial<(X, T), (Y, T)>;
fn with(self, bundle: T) -> Self::Output {
Axial {
x: (self.x, bundle.clone()),
y: (self.y, bundle),
}
}
}
from bei
.with is decomposing axial into two 1d axes
and putting the same bundle on both
negate x will negate both because both are x
negate y wont do anything
That took a while to enter my melon
But I get it now, thanks!
Any idea how we could work around it? 
im not really sure
Thereβs probably a way to turn this into a tuple I reckon
like the obvious answer is to have a separate method for it, but that leaves the footgun there
i think its interesting that Axial is kinda completely generic
like the fact that you can just use it with pretty much whatever for X or Y
Axial { x: Camera::default(), y: Collider::cuboid(x,y,z) }.with(Transform::IDENTITY) is valid code i believe
lol yeah using this as the bindings block of an action is valid
Bindings::spawn((
Cardinal::wasd_keys(),
Axial {
x: Camera::default(),
y: Collider::cuboid(0.0, 0.0, 0.0),
}
.with(Transform::IDENTITY)
))
i dont know what that means
i think the first step is to constrain it such that it cant be used incorrectly, and only then add api surface to allow configuration in correct intuitive ways
Hmm yes, this is quite the axis you have there
I'm even more interested in fixing it downstream so it works for ahoy π
ahh. in that case just
Axial {
x: (Binding::from(GamepadAxis::LeftStickX), Negate::x()), y: (Binding::from(GamepadAxis::LeftStickY), Negate::x())
}
remove Negate from the one you dont want negated
although im not really sure cus the docs say
/// Inverts value per axis.
///
/// By default, all axes are inverted.
not sure how that would make sense tbh
@inner sky Yes, that's because with just attaches a component to every entity in the present. And during applying, each axis are plain f32.
Presets are the weakest part of BEI. Right now I'm just waiting for BSN to use templates instead π
But I probably could update the docs to clarify it.
Wait, I think I know a good solution to it.
@inner sky could you try this branch: https://github.com/simgine/bevy_enhanced_input/pull/261 ? It should just work.
Thx! I can try tomorrow π
BTW, are you on 0.17?
Yep
Okay, let's consider this as a bug, so I can draft a new patch release after you test it.
Remainder just in case you forgot π
@outer wyvern by any chance you missed https://github.com/simgine/bevy_enhanced_input/pull/248 ?
Went ahead and drafted 0.20.1 π
I did! I was working through my notifications
It's quite old (Nov 14), so I decided to ping π
I indeed forgot, sorry!
Will try to remember to check tomorrow
but it very much looks like it will fix it π
Hi, how can i mock action input?
I read docs, but i have multiple entities with same actions (player, NPCs, etc..):
fn mock_jump(mut commands: Commands, jump: Single<Entity, With<Action<Jump>>>) {
commands.entity(*jump).insert(ActionMock::once(ActionState::Fired, true));
}
so this jump query can find only one random entity, but i need mock input for specific entity.
p.s. i need this because in bevy_ahoy BEI is only one way to pass orders to char controller.
I figured it out, I'll leave the solution for those who will do something similar:
sysparam for simlicity:
#[derive(SystemParam)]
pub struct SupPawnMovementInput<'w, 's> {
actions_movement: Query<'w, 's, &'static Actions<ICPlayerMovement>>,
action_jump: Query<'w, 's, &'static Action<Jump>>,
commands: Commands<'w, 's>,
}
impl<'w, 's> SupPawnMovementInput<'w, 's> {
pub fn jump(&mut self, pawn: Entity) -> Result<(), BevyError> {
let movement_actions = self.actions_movement.get(pawn)?;
for action_entity in movement_actions {
let Ok(_) = self.action_jump.get(action_entity) else {
continue;
};
self.commands
.entity(action_entity)
.insert(ActionMock::once(ActionState::Fired, true));
}
Ok(())
}
}
system that apply "jump" to some character:
pub fn on_player_jump(
// .. magic
mut movement_ctl: SupPawnMovementInput,
) -> Result<(), BevyError> {
let player: Entity = {..some query code..}
movement_ctl.jump(player)?;
Ok(())
}
p.s. this is not best solution, because we need loop over all input actions, but i dont now how do better.
If you know which entity you want to mock, you can just iterate over Actions<YourContext> which holds entities of the related actions.
There is also Query::iter_many for convenience: you can pass Actions<C> to it.
if and when this gets merged
https://github.com/bevyengine/bevy/issues/17647
itl be even easier since you could just do
fn on_player_jump(mut commands: Commands, action: Single<Entity, (With<Action<Jump>>, RelatedTo<ActionOf<Player>, With<Player>>)>) {
commands.entity(*action).insert(ActionMock::once(ActionState::Fired, true));
}
assuming I understood the proposal right of course 
any example on moviment with "drag" controls on mobile? i.e., touching the left side of the screen and dragging will create Vec2 movement input from the difference of the initial position and the current location of the touch
We don't expose touch controls yet :(
But it's very easy to implement.
Just add another variant here: https://github.com/simgine/bevy_enhanced_input/blob/356a439d083c2da4d88ccde8153b4bb66164823a/src/binding.rs#L43
And read it from Bevy here: https://github.com/simgine/bevy_enhanced_input/blob/356a439d083c2da4d88ccde8153b4bb66164823a/src/context/input_reader.rs#L73
If you're interested, I'll be happy to accept a PR. It just requires actually playing with the API to expose actually convenient way to bind touch controls.
Has anyone ever complained about having Gizmos on a On<Fire<...>> not working?
Gizmos is immediate. So the event should fire every frame.
is there an example of using picking together with BEI for shortcuts?
E.g., you have 2 sprites right clicking one does one action on it, right clicking on the other does the action on the other, left clicking on one does a different action on it, etc, is that it?
Yes, this should fire every frame. Maybe Gizmos can't be drawn from observers. Try using it in a system.
No, I think after upstreaming we need to rework picking to use BEI under the hood.
One thing that just tripped me up in BEI is Chord vs Combo. In VS Code, a chord is where I press, say, cmd+k, then wait a bit, then press something else and VS Code picks up the action (see screenshot).
However, in the all_conditions.rs example, the Chord action only fires if you press 8 and 9 at the same time. This tripped me up because of the difference to VS Code.
I don't really mind, because I suspect BEI is using UE terms, but just thought I'd share in case anyone else comes across this.
Yeah, itβs named after the corresponding modifiers in UE.
But we donβt have to stick to their naming. Could you open an issue?
Iβm not a native speaker, so Iβll leave it up to @outer wyvern to decide π
Sure I can open an issue but my current feelings are that Iβm not that fussed. If we discover every input system and app out there prefers Chord to mean what it means in VS Code, then maybe you might change it, but if not, it may just be worth keeping in mind and/or documenting further.
@sharp warren I've made a Toggle condition. Here's the gist: https://gist.github.com/mgi388/da68cb3e8fe42ee54326f9bb381a1966. Happy to PR this, or someone else to do it, but I'm still proving that this does what I want for my own use case (and tidying up an example), so haven't done it yet.
One question I had is regarding BEI users and whether they should prefer to mutate a condition (like Toggle), or if they should mutate the ActionState. To elaborate: When an action is toggled on, the BEI user may eventually wants to programmatically toggle the action off. There are two options:
- They could query
&mut Toggleand sett.toggled = false, or; - They could set the action entity's
ActionStatetoActionState::None(which is whatToggle'sevaluatefunction ultimately does underneath when thetoggledmember isfalse.
cc @inner sky because you wanted Toggle too.
To me, chord is natural because of the meaning in music (multiple notes played together)
that's what I've assumed the name comes from
Looks useful!
About mutation, I'd expect to mutate Toggle if needed. This will be consistent with other conditions and modifiers.
the notes of a chord dont necessarily have to be played simultaneously (ex. strumming) or even overlapping (ex. arpeggio) for it to be a chord technically
anyways it would be funny to take the music analogy further and call vs code's notion of chords "melodies"
So yeah, feel free to PR. The snippet looks good!
But a quick note - I prefer to avoid commenting asserts. Just my preference π 2 reasons:
- You can write a panicking message. So this:
// Initially off
assert_eq!(
condition.evaluate(&actions, &time, 0.0.into()),
ActionState::None
);
Can be written like this:
assert_eq!(
condition.evaluate(&actions, &time, 0.0.into()),
ActionState::None,
"Should be off initially"
);
- In most cases it's obvious what's happening. Like in the example above. So I most cases I omit messages entirely. There is no need to duplicate Rust in English π
Agreed, will adjust that before the PR. Thanks for the pre-review!
yes indeed, thanks π
My experience with "chord" is from piano and music, where all elements are played at once
IMO chord generally means "a bunch of things at once". This is true for music, emacs, etc. whereas a "combo" is a series actions in succession (like a fighting game).
I think vscode is an outlier here, and it has been documented in their issue tracker as being weird multiple times, with the ultimate reasoning being "we're going to continue stretching the meaning of the word": https://github.com/microsoft/vscode/issues/155556
emacs chord reference: https://www.emacswiki.org/emacs/Chord#chord
Thanks for doing that research, that's really useful to know it's possibly an outlier in this regard.
Interesting, thanks for the clarification!
@ionic sundial should we close the issue?
Yup just close. Feel free to link Chrisβ reply too if you like.
@inner sky a while back you asked about NPCs and input mocking things. #1297361733886677036 message
Is your thinking there that if an NPC can jump, then you also give it BEI components, and notably a Jump action. But you drive the state of that action not from bindings but from an ActionMock? So if you have some AI script thing that says the NPC is meant to jump now, you'd handle that part of the script by adding an ActionMock to the NPC's action entity?
And either your generic Jump handlers/systems would kick in to make the NPC jump (just as the player jumps), or, if NPCs had a different behavior for jumping maybe there are some slightly different jump handling systems for those.
I think it's an interesting approach that I hadn't really thought of. I tend to think of my BEI components and actions as existing on a "Player" entity, of which there's generally only one (ignore multiplayer things).
My use case is an RTS, and I currently have actions on a "Player" entity, and it represents what you can do to the selected unit only. But I'm thinking whether it makes sense for every unit to have all these actions as well, and to drive the enemy units using mocked values (coming from AI scripts, etc.).
I'm getting an error when trying to use a re-exported version of this crate.
I'm trying to define an InputAction:
use my_crate::enhanced_input::prelude::*;
#[derive(InputAction)]
#[action_output(bool)]
pub struct HoldBreath;
issue is the macro tries to reference ::bevy_enhanced_input::prelude::InputAction which doesn't work because InputAction now lies under ::my_crate::enhanced_input::prelude::InputAction, can't the macro just refer to InputAction directly as it should be inscope if one uses the macro?
It's considered a bad practice to rely on things in scope because macro just substitutes text.
Is there any way to get around this error other than changing the reference then?
I don't think it's possible. You need to depend on the crate directly.
Or what if the reference was changed to bevy_enhanced_input::prelude::InputAction instead, this way it would generally always target the crate but in my case I could write
Use my_crate::enhanced_input as bevy_enhanced_input
But why you even do something like this?
I want to define the version of an external crate in the crate I use it in and then export all external crates for use in crates that depend on it so I have one place that defines the external crates version for all dependencies
It's possible, but uncommon. In macro references usually done via ::path::to::something to avoid clushing. Even though it's unlikely to have a module called std or bevy_enhanced_input.
So I'm not sure.
I'd suggest to avoid doing so. Bevy itself also until recently re-exported ron. But removed the re-export and asked users to define the crate in Cargo.toml
If you want to avoid duplicating your deps, you can use workspace.dependencies.
Workspace dependencies feel so clunky but I guess I have no choice
(because what if I want to reuse crates in a different project or publish them independent of their workspace)
I don't know, to me crate_name::subcrate::thing_you_need is worse than thing_you_need.
For similar reasons Bevy no longer re-exports ron. Or never re-exports something like serde.
whats the status on upstreaming?
Alice got sick, so she didn't have time for upstreaming. But I think we'll try to upstream it for 0.19.
We think so, yeah
@outer wyvern could you review these 2?
https://github.com/simgine/bevy_enhanced_input/pull/262
https://github.com/simgine/bevy_enhanced_input/pull/269
I think it's a much better default.
Otherwise when you change your speed, things like camera controls will also work faster, which is not what user would expect. Or when you pause your game...
Aye-aye. Release is out, so now we can pester Alice I see :p
I'm a bit confused on how you could bind both mouse_motion and Axial::left_stick() to the same action
Like I'm trying to do:
(
Action::<CameraRotate>::new(),
Bindings::spawn((
Binding::mouse_motion(),
Axial::right_stick(),
))
),
Oh never mind, as soon as I find an example with it...
(
Action::<Rotate>::new(),
Bindings::spawn((
// Bevy requires single entities to be wrapped in `Spawn`.
// You can attach modifiers to individual bindings as well.
Spawn((Binding::mouse_motion(), Scale::splat(0.1), Negate::all())),
Axial::right_stick().with((Scale::splat(2.0), Negate::x())),
)),
),
Will be simpler with BSN π
Spawning hierarchies in Bevy is not super convenient right now.
Just switched my control scheme over and am still trying to familiarize myself. How do I distinguish between a button push and a button hold?
I know it's probably in conditions.
You just assign a condition and the action will trigger when you want.
For example, If you want hold - attach Hold condition. If both - create 2 separate actions, one for hold and one for push.
@sharp warren Any chance you've come across this?
.../index.crates.io-1949cf8c6b5b557f/bevy_enhanced_input-0.20.1/src/condition/fns.rs:48:50:
called `Result::unwrap()` on an `Err` value: QueryDoesNotMatch(593v0, ArchetypeId(876))
stack backtrace: <snip>
I don't have a repro, and I couldn't find an existing issue or bugfix in newer versions.
This is happening in 0.20 after upgrading from 0.18 to 0.20 as part of my project's Bevy 0.16 -> Bevy 0.17 upgrade.
Not 100% sure, but I think it's happening when I do a state transition (in this case I tried to end my battle which transitions to a different state).
Don't think it's useful, but link to the full stack trace: https://gist.github.com/mgi388/27afa2a24d78e6f2cbc271f69c2877a6
This should never happen π€
If a condition is removed, it should've been previosly added.
I do lots of DespawnOnExit BTW, including on my BEI player entities.
app.add_systems(OnEnter(Battle), setup_battle_player);
app.add_systems(OnExit(Battle), teardown_battle_player);
// ...
fn teardown_battle_player(mut commands: Commands, player: Query<Entity, With<BattlePlayer>>) {
let Ok(player_entity) = player.single() else {
error!("Battle player not found"); return;
};
commands
.entity(player_entity)
.remove_with_requires::<BattlePlayer>() // necessary to fully remove the context
.despawn_related::<Actions<BattlePlayer>>();
}
I checked the end of the stack trace which I missed when uploading, but it has:
Encountered a panic when applying buffers for system `engine_battle_player::teardown_battle_player`!
Encountered a panic in system `Pipe(bevy_state::state::transitions::last_transition<engine_battle_state::Battle>, bevy_state::state::transitions::run_exit<engine_battle_state::Battle>)`!
So I wonder if the remove_with_requires and/or despawn_related possibly combined with DespawnOnExit is creating some bad state in the ECS/BEI.
I wonder why entity might not exist at this point π€
On each action and binding we basically store a special component with ordering. And the observer fails to access it.
It's an easy fix, just turn it into if let, but I wouldn't expect this to happen... That's why I simply unwrapped.
Drafted a patch release with a new feature: automatic state activation/deactivation based on states.
@sharp warren while continuing my upgrade to Bevy 0.17 I have another weird bug. Again, I don't have a repro sorry, but thought I'd see if you have any ideas off the top of your head. Sometimes when I load my game my context actions appear to be missing. By that I mean: There is an entry in the Actions<C>.entities Vec but there's no actual entity there. Further, sometimes some of the actions are there, but not all of them. Some egui inspector screenshots should help illustrate.
Look at my GlobalPlayer context's Actions (first screenshot). 7 entries, but no entity data. The GlobalPlayer actions are spawned like this and there's no dynamic disabling or removal of entities on my side, and recall that sometimes they're there.
If we look at another of my contexts that exists at the same time, DeploymentPlayer, we see that there's one of the actions there, but the others are just empty entries (second screenshot). The DeploymentPlayer actions are spawned like this. Now, these actions do have some DisabledOnEnter/EnabledOnExit components so I can disable them depending on the state, but I don't think this is related because a) GlobalPlayer doesn't do this and b) RepositionToCursorOrderAction looks the same as all the others, and from the second screenshot you can see this action shows and c) I also disabled these side effects of these components and it still happens.
Again, sorry I don't have a repro yet and I doubt you can do much, but thought I'd ask if anything stands out to you. I don't see any panics or error logs either. Just sometimes it works, sometimes they appear broken. If the entities themselves looked fine I'd probably think system ambiguity, but because of the broken actions it looks like something else. This is [email protected] and [email protected].
This is super weird π€
It feels like the spawning of related entities is broken.
I've never encountered anything like this before. The only cause I can think of is a duplicate Bevy dependency. Could you check that?
Yep I checked. No duplicate dependency.
It definitely is strange. Very likely could be user error of course. Itβs just suspicious that 0.16 was fine.
Iβm not using the macro in the snippets above. I could try switching to the macro just in case that is it.
You could try, but I'd expect it to to be the same π€
Yeah I figured too.
Can you try updating to 0.18?
I can eventually, but waiting on some deps so itβs not easy yet.
That said, itβs fine. Just thought I would check if you had any obvious clue why it could be broken. My next steps is to start to break it down into minimal repro, or I might see if I can update the remaining 0.18 deps myself.
You can try updating the deps to 0.18 or see if they were already updated by someone and use these branches.
Yep Iβve got a tracking issue of all outstanding deps. Thereβs just a few like bevy_mod_scripting that might be hard for me to do so Iβve typically just waited.
Ah, bevy_mod_scripting is quite complex. But update from 0.17 to 0.18 is very simple. We didn't get many breaking changes this time. So I'd give it a try, it might be just a version bump.
This still happens in Bevy 0.18 BTW:
.../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_enhanced_input-0.22.2/src/condition/fns.rs:48:53:
called `Result::unwrap()` on an `Err` value: QueryDoesNotMatch(611v0, ArchetypeId(795))
If I change this in my teardown function:
commands
.entity(player_entity)
.remove_with_requires::<BattlePlayer>() // necessary to fully remove the context
.despawn_related::<Actions<BattlePlayer>>();
to this:
commands
.entity(player_entity)
.remove_with_requires::<BattlePlayer>(); // necessary to fully remove the context
// .despawn_related::<Actions<BattlePlayer>>();
(i.e., remove the despawn_related call)
It doesn't crash. And for completeness, removing remove_with_requires, but keeping despawn_related also crashes.
Still striving to get a repro for you but wanted to share an update re still not working in Bevy 0.18 (have only just upgraded / in the middle of it).
Also just noting this one still exists in Bevy 0.18 as well. That is, actions missing sometimes / Actions<C>.entities Vec containing entries with invalid/missing entities.
This is weird. Could you try to create a minimal repro for both?
@sharp warren I believe I have a repro for this one: https://github.com/simgine/bevy_enhanced_input/pull/279 See PR description for more info.
Thanks, I'll fix it today after work!
@inner sky if you're looking for a wall of text to read now that you're back, I'm keen to hear your thoughts on this. But if you're too busy or not interested, all good!
yep that's precisely it π
though because BEI / Bevy have no good input buffering story, I need some intermediate representation anyways (to keep the input around until the next fixed update)
so as a consequence in my API, you can still opt to not use mocks at all and directly modify that cache
Yeah I saw your repo where you accumulate the input and I was inspired by that to do the same.
let me know how it works for you π
I'm also curious to see how this scales in the long run!
Will do! I'm still doing lots of massaging and will start doing some reworking soon to store actions per unit rather than on the "player".
@ionic sundial fixed: https://github.com/simgine/bevy_enhanced_input/pull/280
@sharp warren is there a cleaner way to mock a specific action?
fn set_controller_velocity(
mut agent_query: Query<(&Agent, &Actions<NpcInputContext>)>,
mut action_mocks: Query<&mut ActionMock>,
desired_velocity_query: Query<&LandmassAgentDesiredVelocity>,
global_movements: Query<(), With<Action<GlobalMovement>>>,
) {
for (agent, actions) in &mut agent_query {
for action in actions {
let Ok(mut mock) = action_mocks.get_mut(action) else {
error!("Failed to get action mock");
continue;
};
if global_movements.contains(action) {
// use mock
}
}
}
}
if no, would you mind if I upstreamed an analogue to seedling's get_effect?
Maybe something like
fn set_controller_velocity(
mut agent_query: Query<(&Agent, &Actions<NpcInputContext>)>,
mut action_mocks: Query<&mut ActionMock>,
) {
for (agent, actions) in &mut agent_query {
let mut mock = action_mocks.get_mock::<GlobalMovement>(actions).unwrap();
// use mock
}
}
There is iter_many_mut which should be a bit more ergonomic π€
So you just iter_many_mut(actions).next()
I would really prefer to have a better generic solution built into Bevy, but I don't mind adding a trait extension in the meantime π
you forget, iter_many_mut does not have the same ergonomics as iter_many 
that bit me many times too
oh, though in this case it doesn't matter
hmm nvm, that doesn't play too well with the fact that it needs to be GlobalMovement
iter_many_mut cannot be chained into filter
Yeah, it's not an iterator :(
fn set_controller_velocity(
mut agent_query: Query<(&Agent, &Actions<NpcInputContext>)>,
mut action_mocks: Query<(Entity, &mut ActionMock)>,
desired_velocity_query: Query<&LandmassAgentDesiredVelocity>,
global_movements: Query<(), With<Action<GlobalMovement>>>,
) {
for (agent, actions) in &mut agent_query {
let mock = action_mocks
.iter_many_mut(actions)
.fetch_next()
.filter(|(e, _)| global_movements.contains(*e))
.map(|(_, mock)| mock)
.unwrap();
}
}
this ugly duckling works
This will get only the first action
So yeah, if you want eronomically get action X for context Y, we need either better Bevy support for it, or do something custom.
I heard we're getting hierarchy queries in the next release, though π€
This?
fn set_controller_velocity(
mut agent_query: Query<(&Agent, &Actions<NpcInputContext>)>,
mut global_movement_mocks: Query<&mut ActionMock, With<Action<GlobalMovement>>>,
desired_velocity_query: Query<&LandmassAgentDesiredVelocity>,
) {
for (agent, actions) in &mut agent_query {
let mock = global_movement_mocks.iter_many_mut(actions).fetch_next().unwrap();
}
}
Pinging @brittle swallow because you also care about this
This would work
(e.g. what bevy_seedling does seems like an excellent upstreaming candidate, though not exaaaactly what we need here)
nope, good old "temporary value dropped while borrowed"
fn set_controller_velocity(
mut agent_query: Query<(&Agent, &Actions<NpcInputContext>)>,
mut action_mocks: Query<&mut ActionMock, With<Action<GlobalMovement>>>,
desired_velocity_query: Query<&LandmassAgentDesiredVelocity>,
) {
for (agent, actions) in &mut agent_query {
let mut iter = action_mocks.iter_many_mut(actions);
let mut mock = iter.fetch_next().unwrap();
}
}
oof this is suboptimal
not your fault ofc
that's just missing ergonomics in the ECS
@sharp warren is this syntax fine for you as an upstreaming solution until we have something better builtin?
Oh, while on the topic: how do you feel about implementing Default for ActionMock?
Yeah! We can remove it once not-needed. Not a big maintenance cost.
Another option to consider: make this API event-based.
could you elaborate?
Good idea. I'd probably would even make it required component for actions. So we won't have archetype moves when we want to mock.
asking because I have to spam a ton of these guys for all my actions:
ActionMock {
state: ActionState::None,
value: Vec3::ZERO.into(),
span: MockSpan::Manual,
enabled: false
}
that would be excellent 
is same PR alright?
"improve mock ergonomics"
Instead of adding an extension trait, we can create a special event that targets context and specifies the action we want to mock.
π I like the way you think
Up to you, both separate and the same PR fine by me π
that would have lovely semantics
Yeah, easier to write. You just add Commands to your system.
fn set_controller_velocity(
mut agent_query: Query<(Entity, &Agent)>,
mut commands: Commands,
) {
for (context, agent) in &mut agent_query {
commands.trigger(
Mock {
context,
ActionMock::new(...)
}
);
}
}
like this?
Yep!
Wait, you also need action type
hehehe, I was about to ask "how do you feel about ActionMock::once?"
apparently you feel good about adding that π
We won't be able to observe this way π€
It needs to be dynamic.
commands.trigger(
Mock {
context,
action_type: GlobalMovement.type_id(),
ActionMock::new(...)
}
);
would that work? 
it's surely ugly
Just make the constructor generic
oh good idea
I.e. you pass the type into constructor and it stores the TypeId internally.
If you don't mind currying, this would even work: (sec)
You will need to convert TypeId into ComponentId via type registry
commands.entity(context).trigger(
Mock::new::<GlobalMovement>(ActionMock::once(...))
);
And later find an entity in Actions that stores type
where Mock::new actually returns an Fn
Wait, Actions is generic π€
ah heck
you know what, I'll do the extension trait for now
I bet there's a neat design here that can be dug up
but we can still switch to it later
Wait, I think I have an idea.
We can have a custom command. It can be fully generic.
You'll have to help me out here for sure haha
commands.mock
ooooooh
commands.entity(context).mock::<GlobalMovement>(ActionMock::once(...));
It's easy to implement. We just need to create a struct MockCommand and implement Command trait for it. The struct will be generic over action and context.
And finally you add an extension trait for Commands to do mock.
Yeah, something like this.
But you need to write both context and action type.
oh yep
commands
.entity(context)
.mock::<NpcInputContext, GlobalMovement>(ActionMock::once(...));
For example you can take a look at something like AddChild in Bevy
It's also a custom command.
yeah I know about those, I was thinking in the wrong direction earlier π
alright I can do that
brb coding it up
@sharp warren this would require : Reflect for the involved input action and input context
which is fine by me
just mentioning
or well, at least Any
Why so? If the command is generic, you should know the type at compile-time.
but I need the type_id for a dynamic query
or hmm
You needed it for event because we can't observe such event without registration
But it's not the case for command. If your struct is generic, you don't need dynamic queries
@sharp warren the test fails for some reason, but is this the right shape? https://github.com/simgine/bevy_enhanced_input/pull/282
Yep!
A few suggestions:
- I think you can just
world.get::<Actions<C>>if you place it after thequery_filtered. - I'd use
Cfor context type andAfor action type for consistency. - Could you rename
_pdintomarker? Just for consistency with the rest of the codebase. - I'd rename the test into simply
entity_command.
Also, maybe do mock_once command as well?
on it
Instead of this
.mock::<TestContext, Test>(ActionMock::once(ActionState::Fired, true));
do this:
.mock_once::<TestContext, Test>(ActionState::Fired, true);
And .mock can look like the default constructor. To avoid typing ActionMock
good idea π
check again
Now why is it not actually mocking anything 
the places with ? are all returning Ok
Oooh
It has a one frame delay like this
One update to queue the command, one for applying the mock
Hrmm
Got any wisdom?
Ah, of course. It's because you using commands on the world. It's fine.
Fair enough
Maybe we need to implement this extension trait for both world and commands. I did similar thing in Replicon.
it would still take 2 frames in userland code, no?
On second though, it's not that useful on the world π€
i.e. when calling it in a system
yeah I meant in a regular system that uses Commands
oh, no
Hm, no sure tbh
no it wouldn't
since the ActionMock will be handled the next frame by BEI
all good
then I'm happy with it π
my doc example is not quite right, gonna fix that
also, IIRC we agreed that consuming inputs should be false by default, right?
I don't remember agreeing on this π€
been a while haha
I think it will be less confusing for users π€
I walked right into a footgun with Ahoy due to the input consumption where I bind multiple things to the same key by default
so I right now have to tell consumers "please make sure to set that to false"
Yeah, not great.
I can do a second PR for that
IMO yes: this is something that is unreachable
using a Result there would be the wrong semantic
ideally this would be rewritten so that the type system knows this fact
but idk how without having a multiple borrow
(assuming you mean the .expect())
Ah, right!
I'd only suggest to change the messages a little:
- Include actual type to make them more clear.
- Start messages with a non-capital letter (both panics and errors). That's how it's done in the crate and that's what Rust std lib does.
How do I get the actual name?
Just use ShortName
Check other places in the crate for usage examples
the expect needs to stay like that because World is a type, and Rust recommends that style for expect ("I expect that blablabla")
but alright for the others π
TIL, that's neat
If it's a type, I'd wrap it into `
And what do you think about
expect('ActionMock' already found on this entity)
Can't use ` inside code fences, weird π
good idea!
done
PR should be good now 
Maybe move ActionMock and the extension trait into a separate mock module under action?
can do
Looks good, I'll make a proper review pass (just in case) today later because I'm currently at work π
done 
sounds good! I'll do the other PR now
let's hope all tests pass without a change hehe
Doubt it π
I'll keep my hopes up 
you were right, of course
aight, fixed those
nothing dramatic
PR ready too π
Great, I'll take a look later today π
Reviewed, thanks!
Once merged, I'll draft a new release.
@sharp warren I've addressed everything except this:
I'm looking at the Bevy code for EntityCommand and looks like they do it differently nowadays. The idea is to create an extension trait for EntityWorldMut first with mock and mock_once. And then create a function that returns a closure that simply calls this method. And finally create an extension trait for Commands that queues this function. This way you have a convenience for both Commands and direct world access.
could you point me to the code in the Bevy codebase you're referencing?
I fail to understand what exactly you mean
Sure!
Take a look at this module:
https://github.com/bevyengine/bevy/blob/5925b1925841149a6df99beda0c4d831c53d4556/crates/bevy_ecs/src/system/commands/entity_command.rs#L112
Their entity commands are just plain functions.
So instead of having a struct, you just implement your extension trait for β¨EntityWorldMutβ© that does the thing directly.
And just create a function that returns β¨EntityCommandβ©.
And finally implement the extension trait on β¨Commandsβ©. This way you have both: command and entity API.
Feel free to ask questions if anything is unclear.
@outer wyvern I noticed you approved all PRs except https://github.com/simgine/bevy_enhanced_input/pull/280
By any chance you missed it?
aah perfect, thanks!
will implement that later
Made a few tiny changes, see commits. Let me know if you want me to handle the suggestion about commands.
just saw it, thx
I'll be going to IKEA now, so feel free to implement it if you happen to have time π
otherwise I'll do it when I return
I'm also need to go rn π
hehe
Missed it; not back at work so the notification sampling is random
Got it, sorry for bothering!
@sharp warren we're missing these register_types (first screenshot) (they're not automatic because of generic type parameters). But to do that we need to add the + TypePath constraint (second screenshot). Which means deriving TypePath on contexts (third screenshot).
Would it be OK to PR this change like this? It would force everyone to add TypePath to their context components. But because the BEI crate doesn't yet have a conditional bevy_reflect feature (or reflect, whatever the name), it would be a bigger change to introduce that feature at the same time.
I guess it's probably going to be better to first introduce a reflect feature before making this change, isn't it...
Use case: self.register_type::<Actions<C>>();, for example, lets me look at and expand the actions in my inspector.
Ah, yes, requiring β¨TypePathβ© is exactly why I didn't call β¨register_typeβ©.
I think requiring β¨TypePathβ© will reduce the ergonomic. I don't like deriving β¨TypePathβ© for every context π€
I guess I can continue to do this in user land, itβs just less convenient.
Alternatively, I guess a BEI reflect feature would avoid forcing everyone to derive TypePath unless they want to enable that feature.
I don't know, I think it's convenient to have reflect enabled to see things like β¨β¨ActionValueβ©β©, but at the same time requiring contexts to implement β¨β¨TypePathβ©β© is a bit invasive...
Maybe we can have an alternative registration methods as a workaround? π€
Could you open an issue to discuss this with others?
Yeah Iβll open an issue. I personally donβt think itβs invasive to have to derive reflect or typepath on my components. All of my components derive reflect as a matter of course anyway (I need to do this so I can use an inspector) and you have to derive typepath on asset loaders to make them work as well, so itβs no big deal IMHO to have to do this.
And yeah a second trait method is also an option (and is what I am currently doing in user land).
Also you probably have way more components in your game than you have context components so I suspect thereβs only a handful of context types most games would ever have to add TypePath to.
All that said, if it was conveniently gated behind a feature then maybe everybody wins.
Will make an issue later.
I agree that having β¨#[require(Component, TypePath)]β© (or β¨Reflectβ©) is not a big deal, but feels a bit wrong to require this... π€
Let's discuss this in a issue. I can't say which solution I would prefer.
But we definitely should make reflection optional, it's 100% a good start.
I would personally also prefer contexts be type path, it seems very acceptable in practice
done 
Thank you!
I need your opinion π
If we return β¨β¨Errβ©β© from β¨β¨Commandβ©β©, the app will panic, right?
Do you think it's desirable? This doesn't sound like a critical error to me, maybe just log a warning if there is no such action?
I found panics in gamedev quite annoying for development π
A warning would allow me to inspect the entity in the inspector. Once we get editor, this may become even more desirable.
Another advantage is that we'll able to have a single extension trait for both β¨β¨EntityWorldMutβ©β© and β¨β¨EntityCommandsβ©β©.
No! It will call the default error handler, which is slated to respect error levels (critical, warn, info, etc)
so the general advice right now is to expose as many things as possible as β¨Resultβ©s so that the error handler has the power to handle them accordingly
and since panicking is crap, most people right now should switch the default error handler from panic to log imo
but that's an on ongoing ECS design thing
so IMO we should definitely return a β¨Resultβ© there
any panics resulting from that are not a BEI fault, but a default error handler fault
last few times this was discussed, the outcome was "don't assume β¨Errβ© == panic for your designs"
Ah, right, thank you!!
the one place where we did an exception for this was β¨Singleβ©, which should return a β¨Resultβ©
but its panickyness was already changed a few times
and it's very very likely that when we have error levels, it will go back to warnings or being ignored again
so in order to not have it switch yet again, we decided to wait with that
Makes sense π
@inner sky Thank you a lot! Love this API.
Pushed a few minor changes from my side π
LGTM π
thx
Once merged, I'll draft a new release
@thick kiln I need your answer on https://github.com/simgine/bevy_enhanced_input/pull/266#discussion_r2657711427 π
To put it short, I think you simply can add β¨whereβ© in your code instead and it should just work since the action is already serializable.
I just think it's might be a better place to do so.
let me check; so the PR is not needed?
Yeah, I think so π
Unless you're working with generic functions over β¨InputActionβ©, but in this case I'd just add β¨whereβ© in your code.
@sharp warren I've given you a couple of reviews now π
Awesome, thanks!
I have been thinking... We probably should go with the β¨TypePathβ©. I think it's a lesser evil.
If you open a PR, I'll bless it.
But we need to mention it in the quick start guide.
Ok sounds good Iβll take a look at it. I can update the docs and quick start guide.
@sharp warren @inner sky I started using the new mock_once but I've come across an issue I'd like to get your thoughts on: After usingmock_once, bevy_enhanced_input unconditionally sets enabled = false after expiry, breaking AI-controlled actions.
Use case: I'm using ActionMock for AI-controlled units. When spawning actions, I use ActionMock::new(ActionState::None, false, MockSpan::Manual) to keep the mock enabled (so AI can drive the action). When a unit is player-selected, I set enabled = false so real input bindings work. When deselected, I restore enabled = true for AI control.
The problem: When I call mock_once() to trigger an AI action, after the mock span expires, the code in context.rs sets mock.enabled = false. This makes the AI lose control. The action returns to "player-controlled" state instead of staying in "AI-controlled/mocked" state.
Any ideas? Could ActionMock support restoring to a configurable enabled state after expiry (rather than always false)? For example, a restore_enabled: bool field, or treating MockSpan::Manual differently since it already implies manual lifecycle control?
I'd expect AI to regain the control after user. I.e. give a different value.
Yeah I guess it can be controlled in user-land. I'm doing this at the moment. Not sure if this will scale / will reveal any future design issues, but this seems to work for now:
app.add_observer(restore_action_mock_after_complete::<CancelOrderAction>);
fn restore_action_mock_after_complete<A: InputAction>(
complete: On<Complete<A>>,
mut commands: Commands,
unit_query: Query<(), Without<UnitSelected>>,
) {
// If the unit is not selected (i.e., AI-controlled), restore the action
// mock. If we don't do this, the action mock remains disabled and the AI
// ends up responding to bindings meant for player-controlled units.
if unit_query.get(complete.context).is_ok() {
commands.entity(complete.action).insert(ActionMock::new(
ActionState::None,
false,
MockSpan::Manual,
));
trace!("Restored AI mock for action");
}
}
I'm not sure if I get it. Why you reset the mock?
The units in the game all have an action context, and of course a set of action entities related to it. Now, by default I add an ActionMock to all of those actions (with enabled=true). This is so that the non-player controlled units do not respond to bindings/input.
When the player selects a unit, I change that entity/unit's actions and set the ActionMock.enabled=false. This is so that the selected unit can now respond to player input/bindings.
Now, to test some really simple "AI logic", I added a system that does this every 1s:
// Get a random non-player controlled unit.
//
// Call "mock_once" to simulate AI logic where the unit is canceling its current order.
commands
.entity(unit_entity)
.mock_once::UnitInputContext, CancelOrderAction>(ActionState::Fired, true);
This works as expected. However, once BEI is done executing this mock, and it has expired, BEI sets the ActionMock.enabled=false (per the context.rs link I shared above).
But now refer back to the start of this message: "I add an ActionMock to all of those actions (with enabled=true)". I need the AI units to have their ActionMock.enabled=true so that they don't respond to player input/bindings, but BEI just set it to false!
Is that a bit clearer?
Ah, I get it now!
Yes, right now I'd probably reset it like this.
I wouldn't expect the old state to be restored π€
I could imagine a BEI API like:
commands
.entity(unit_entity)
.mock_once::UnitInputContext, CancelOrderAction>(ActionState::Fired, true)
.and_then(OnActionMockExpired::SetEnabled);
(this is just pseudo-code, no idea how the API should actually look here, e.g., it could just be another arg to mock and mock_once)
I think part of the reason there is a tension here is that mock_once and mock are sending off non-zero values for the action mocks (and with enabled: true to indicate the mock should now be in effect). But I'm trying to have the default state of the actions with an action mock that also has enabled: true, but with zero values for the action mock.
Said another way, it feels wrong to me that BEI unconditionally sets enabled=false once the mock has expired, because using the mock as an "always on" (i.e., with enabled: true), but sometimes with non-zero values seems like a valid thing to do.
Happy to be proved that this is the wrong thinking though.
The purpose of mock is to force specific value. Once the span expires, the component disables itself. I disable it instead of removing to avoid archetype moves.
I'd probably suggest to rethink the strategy itself. I think and_then is a bit too opinionated. But you can build an abstraction like this in your code, of course.
I think and_then is a bit too opinionated
Yeah it was just pseudocode to illustrate callers trying to say "restoreActionMock.enabled"
I understand, I mean I'm not sure about adding a configurable condition like this...
But I can add an event that indicates the mocking is over. What do you think?
Might be more convenient to attach your logic this way.
Ah got you, my bad. I thought you were commenting on the specific syntax.
An event sounds like it could be more declarative / clearer intent for what the user-land "restore" code does (compared to my current approach relying on the Complete event).
And a bit more efficient. I think having an event for this is useful in general. Feel to open a PR or an issue.
I am also happy to keep thinking about this and seeing if my design should be reworked though.
@inner sky I wonder if we could have try_ versions of entity commands mock and mock_once (by using queue_silenced I believe).
Why? It's easy to experience the panic entity 462v0 has no Actions<MyInputContext> when you're spawning and despawning contexts (e.g., when using context layering) intertwined with mocking.
mock and mock_once probably also need to have their docs updated to mention they can panic.
They donβt panic. This is the fault of the default error handler in Bevy controversially treating errors as panics
Oh lol not this again.
Right, so if my error handler warned and didn't panic, I'd have the error warned, right?
But does my comment still stand insofar as "well, I can't do anything about this warning, the context no longer exists, so if we had try_ versions I'd use call that to indicate I don't care about it failing"?
Well we have remove and try_remove, so that would be consistent
we could do the exact same thing for try_mock π
Yup. I'll make an issue to track it, don't have time rn to make a PR for it, but will try and get to it later.
hmm
actually, we could override the error handler for mock as well
so that it prints a warning
Ah so for my case even though I have the panic error handler I would now get the warn instead. That would be a better default state I think, but I'd still use the try_ ones to avoid warning log spam.
yeah fully agreed on both accounts
honestly, the issue here is that error handling is a bit messy in Bevy
but let's at least be consistent
I'll whip up a PR rn
I happen to have a bit of time
Amazing thanks, if you're free go for it.
Yeah I have an overall average experience with Bevy error handling (not great, not the worst), but I don't personally have any great ideas or suggestions to make it better.
Lmao the amount of times I can't work out why a system isn't running and I've yet again forgotten that it was skipped due to a Single query no longer matching.
But that's OT.
@ionic sundial @sharp warren https://github.com/simgine/bevy_enhanced_input/pull/290
I've had that happen so many times dealing with replicated components. Is there a way to make it panic (error I guess)?
Actually I guess it should normally? Hmm
Edit: Oh looks like it has flip flopped a few times. That explains it
@ionic sundial @inner sky the patch is up π
I wonder if we could improve the docs for ActionState Ongoing and Fired. When you're trying to understand whether to use ongoing or fired, it's not really clear from the enum variant docs what the actual difference is. To me they read exactly the same. Edit: And I still don't actually know what the difference is.
Ongoing: "For example, with the [Hold] condition, this state is set while the key is held down, until the required duration is met."
Fired: "For example, with the [Down] condition, this state remains active as long as the key is held down."
Context: In my Toggle implementation I am trying to understand if I'd use Ongoing or Fired (I'm trying to solve a bug in my game and checking how my Toggle implementation works).
Explicitly contrasting them would be a good strategy
The documentation you quoted also has these portions that were prior to what you quoted:
ActionState::Ongoing: "Condition has started triggering, but has not yet finished."
ActionState::Fired: "The condition has been met."
Ongoing is used when a condition has some but not all its requirements that need to be met before the condition is active, it is in process though. Fired is when the condition has all its requirements met, so it is active.
In the case of [Hold], the input requirement is met but the necessary time might not have passed so it is set to ActionState::Ongoing. On the other hand, [Down] just requires the input is active and will keep as ActionState::Fired as long as that is the case.
Ah right I think that clears it up a bit, thanks.
I honestly didn't know that Ongoing meant "condition has not been met" π
.
I thought it was the opposite: That the condition has been met. For example, if I say I am having an ongoing argument with someone, the argument has started and is still happening. So I thought this meant the condition was started and is still happening.
English is hard.
Perhaps ActionState might be better named ConditionState since it may help someone consider that the Condition can be Ongoing even if the Action isn't active. I think Press is an example of using Ongoing to prevent further firings until the input has been released and then pressed again. In that case, the ActionState for the Condition goes to Fired and then switches to Ongoing to keep track of the input state.
I was mistaken. It is Tap that uses Ongoing.
I like the proposed name π€
Could you open an issue? I'd like to see other people opinions.
@ionic sundial by any chance you could open a PR to clarify the doc since you understand it properly now?
Yup will do.
wait WHAT
TIL
@ionic sundial Could you include your thoughts on the issue as well?
i'm currently investigating if its possible to allow binding OpenXR input through this (from a thirdparty crate), but i can't find a way to add any custom binding source? is this currently supported?
it would suck if i still had to recommend that users replace their entire input handling system with something else, just because they want to support XR, especially if this is upstreamed into bevy
@inner sky it occurs to me with your thinking here: I wonder if another way to improve the chances of upstreaming BEI and show it's quality is for those new Bevy camera controllers to be upgraded to BEI outside of tree. It's not my call, but even if they lived in BEI so they were also treated as first class citizens, they'd then more easily slot back in tree if BEI was upstreamed. They could just as easily be another 3rd party crate ofc.
It's not currently supported, but we have an open issue about custom input sources.
We just didn't have a use case. Would you be interested to tackle it?
You can replace the underlying input system, but we don't have a way to define custom bindings, like XR.
i think i'll have to investigate if having custom bindings would be enough to support OpenXR, since it provides its own action based input system you have to integrate with, depending on how BEI is built that might need a whole redesign
It's already planned for upstreaming.
I'm just waiting when maintainers have free time. I'm not rushing with this because having it as a third-party crate allows me to interate on it more quickly π
I don't think BEI will need a redesign because I'm pretty sure Unreal Engine suports XR
Sorry I didnβt mean to imply it wasnβt up to scratch (itβs amazing), I was just trying not to assume anything.
I mentioned that more in that it sweetens the deal a bit more of the camera controllers are also already updated.
Another good use case would be shortcuts for buttons. And shortcuts for picking π
Not sure if this is what you mean regarding picking: But yeah Iβd love to see something UI + BEI combined. For example how to make sure clicks on UI elements swallow/consume input so that actions like clicking on your 3d world donβt also fire. I wondered if BEI could somehow provide a UiInputContext with a high priority or something.
Just thinking out loud, can probably do all this in user land easily.
I was playing with UI and BEI last year and I made a Context for UI Navigation that included activating an element. When it activated, it found the currently focused UI element and sent a click event to it. The harder part was setting up navigation but with Bevy 0.18's Automatic Directional Navigation it should be easier.
Here's the function that actually sent the click:
pub fn activate_ui_selection(
_: Trigger<Fired<UiActivate>>,
input_focus: Res<InputFocus>,
mut commands: Commands,
) {
if let Some(focused_entity) = input_focus.0 {
commands.trigger_targets(
Pointer::<Click> {
target: focused_entity,
pointer_id: PointerId::Mouse,
pointer_location: Location {
target: NormalizedRenderTarget::Image(
bevy::render::camera::ImageRenderTarget {
handle: Handle::default(),
scale_factor: FloatOrd(1.0),
},
),
position: Vec2::ZERO,
},
event: Click {
button: PointerButton::Primary,
hit: HitData {
camera: Entity::PLACEHOLDER,
depth: 0.0,
position: None,
normal: None,
},
duration: Duration::from_secs_f32(0.1),
},
},
focused_entity,
);
}
}
BEI allowed me to separate inputs from actions so I could navigate the UI with keyboard and/or gamepad relatively simply. Probably need a little update for newer versions of both Bevy and BEI.
Here is what I use in my game for UI:
https://github.com/simgine/simgine/blob/master/ui/src/widget/button/action.rs
bevy_picking uses hardcoded inputs, but I think it would be nicer to express it through BEI.
Yours is so concise, I like it!
Ooo thanks for sharing. I didnβt know you had anything open source here. Good to see something from the BEI author for possible βbest practiceβ.
already using the new mocking API I see 
Yeah, I really liked it!
I would appreciate opinions on https://github.com/simgine/bevy_enhanced_input/pull/297
See the linked issue. I'm on board, but I'd like to hear what other people think.
(Since it might be controversial / not the only solution, I also updated the PR desc with some more background explaining the goal, the proposed solution and maybe some alternatives)
Thanks!
Asked in #reflection-dev message
Is Mouse Motion an input in this crate?
@outer wyvern if it please you (and when you get a chance, no rush): https://github.com/simgine/bevy_enhanced_input/pull/298
Done! nice stuff
observers are only called when their triggers are all on right?
Yes
Correct
do we really need a whole Action for a modifier here ? I feel it can be simplified to just a bindings entity
Returns ActionState::Fired if all given actions fire, otherwise returns their maximum ActionState, capped at ActionState::Ongoing.
Could you possibly explain further what you mean? I have a use case from another game where I regularly use multiple modifiers with two input devices to change behavior across the input devices. I can use the modifiers individually or together, just like how on a keyboard you can use CTRL and Shift either individually or together. Would a binding entity allow for similar behavior?
I do know how I can replicate that with Actions in BEI, but could you explain your solution?