Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,25 @@ jobs:
- name: Rustdoc
run: cargo rustdoc -- -D warnings

no-std-portable-atomic:
name: Without atomics and std
runs-on: ubuntu-latest
steps:
- name: Clone repo
uses: actions/checkout@v4

# Use the same target platform as Bevy (Game Boy Advance).
- name: Instal stable toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: thumbv6m-none-eabi

- name: Cache crates
uses: Swatinem/rust-cache@v2

- name: Check compilation
run: cargo check --target thumbv6m-none-eabi --features bevy/critical-section

doctest:
name: Doctest
runs-on: ubuntu-latest
Expand Down Expand Up @@ -125,7 +144,7 @@ jobs:
codecov:
name: Upload to Codecov
if: github.actor != 'dependabot[bot]'
needs: [typos, format, lint, doctest, test]
needs: [typos, format, lint, no-std-portable-atomic, doctest, test]
runs-on: ubuntu-latest
steps:
- name: Clone repo
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Serde derives for `ActionState`.

### Changed

- Update to Bevy 0.16.

## [0.9.0] - 2025-04-08

### Added
Expand Down
19 changes: 13 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bevy_enhanced_input"
version = "0.9.0"
version = "0.10.0-rc.5"
authors = ["Hennadii Chernyshchyk <[email protected]>"]
edition = "2024"
description = "Input manager for Bevy, inspired by Unreal Engine Enhanced Input"
Expand All @@ -12,17 +12,24 @@ license = "MIT OR Apache-2.0"
include = ["/src", "/LICENSE*"]

[dependencies]
bevy_enhanced_input_macros = { path = "macros", version = "0.9.0" }
bevy = { version = "0.15", default-features = false, features = ["serialize"] }
bevy_enhanced_input_macros = { path = "macros", version = "0.10.0-rc.5" }
bevy = { version = "0.16.0-rc.5", default-features = false, features = [
"serialize",
] }
log = "0.4" # Directly depend on `log` like other `no_std` Bevy crates, since `bevy_log` currently requires `std`.
variadics_please = "1.0"
serde = { version = "1.0", default-features = false, features = ["derive"] }
bitflags = { version = "2.6", features = ["serde"] }
bitflags = { version = "2.6", default-features = false, features = ["serde"] }

[dev-dependencies]
bevy = { version = "0.15", default-features = false, features = [
bevy = { version = "0.16.0-rc.5", default-features = false, features = [
"bevy_gilrs",
"bevy_ui",
"bevy_gizmos",
"bevy_log",
"bevy_ui_picking_backend",
"bevy_ui",
"bevy_window",
"default_font",
"x11",
] }
ron = "0.8"
Expand Down
2 changes: 1 addition & 1 deletion examples/all_conditions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ fn spawn(mut commands: Commands) {
}

fn binding(trigger: Trigger<Binding<Dummy>>, mut actions: Query<&mut Actions<Dummy>>) {
let mut actions = actions.get_mut(trigger.entity()).unwrap();
let mut actions = actions.get_mut(trigger.target()).unwrap();
actions
.bind::<PressAction>()
.to(PressAction::KEY)
Expand Down
20 changes: 10 additions & 10 deletions examples/context_layering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn spawn(mut commands: Commands) {
}

fn regular_binding(trigger: Trigger<Binding<Player>>, mut players: Query<&mut Actions<Player>>) {
let mut actions = players.get_mut(trigger.entity()).unwrap();
let mut actions = players.get_mut(trigger.target()).unwrap();
actions
.bind::<Move>()
.to(Cardinal::wasd_keys())
Expand All @@ -58,7 +58,7 @@ fn regular_binding(trigger: Trigger<Binding<Player>>, mut players: Query<&mut Ac
}

fn swimming_binding(trigger: Trigger<Binding<Swimming>>, mut players: Query<&mut Actions<Player>>) {
let mut actions = players.get_mut(trigger.entity()).unwrap();
let mut actions = players.get_mut(trigger.target()).unwrap();
// `Player` has lower priority, so `Dive` and `ExitWater` consume inputs first,
// preventing `Rotate` and `EnterWater` from being triggered.
// The consuming behavior can be configured in the `InputAction` trait.
Expand All @@ -67,12 +67,12 @@ fn swimming_binding(trigger: Trigger<Binding<Swimming>>, mut players: Query<&mut
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
let mut transform = players.get_mut(trigger.entity()).unwrap();
let mut transform = players.get_mut(trigger.target()).unwrap();
transform.translation += trigger.value.extend(0.0);
}

fn rotate(trigger: Trigger<Started<Rotate>>, mut players: Query<&mut Transform>) {
let mut transform = players.get_mut(trigger.entity()).unwrap();
let mut transform = players.get_mut(trigger.target()).unwrap();
transform.rotate_z(FRAC_PI_4);
}

Expand All @@ -82,21 +82,21 @@ fn enter_water(
mut players: Query<&mut PlayerColor>,
) {
// Change color for visibility.
let mut color = players.get_mut(trigger.entity()).unwrap();
let mut color = players.get_mut(trigger.target()).unwrap();
**color = INDIGO_600.into();

commands
.entity(trigger.entity())
.entity(trigger.target())
.insert(Actions::<Swimming>::default());
}

fn start_diving(trigger: Trigger<Started<Dive>>, mut players: Query<&mut Visibility>) {
let mut visibility = players.get_mut(trigger.entity()).unwrap();
let mut visibility = players.get_mut(trigger.target()).unwrap();
*visibility = Visibility::Hidden;
}

fn end_diving(trigger: Trigger<Completed<Dive>>, mut players: Query<&mut Visibility>) {
let mut visibility = players.get_mut(trigger.entity()).unwrap();
let mut visibility = players.get_mut(trigger.target()).unwrap();
*visibility = Visibility::Visible;
}

Expand All @@ -105,11 +105,11 @@ fn exit_water(
mut commands: Commands,
mut players: Query<&mut PlayerColor>,
) {
let mut color = players.get_mut(trigger.entity()).unwrap();
let mut color = players.get_mut(trigger.target()).unwrap();
**color = Default::default();

commands
.entity(trigger.entity())
.entity(trigger.target())
.remove::<Actions<Swimming>>();
}

Expand Down
16 changes: 8 additions & 8 deletions examples/context_switch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fn spawn(mut commands: Commands) {
}

fn foot_binding(trigger: Trigger<Binding<OnFoot>>, mut players: Query<&mut Actions<OnFoot>>) {
let mut actions = players.get_mut(trigger.entity()).unwrap();
let mut actions = players.get_mut(trigger.target()).unwrap();
actions
.bind::<Move>()
.to(Cardinal::wasd_keys())
Expand All @@ -56,7 +56,7 @@ fn foot_binding(trigger: Trigger<Binding<OnFoot>>, mut players: Query<&mut Actio
}

fn car_binding(trigger: Trigger<Binding<InCar>>, mut players: Query<&mut Actions<InCar>>) {
let mut actions = players.get_mut(trigger.entity()).unwrap();
let mut actions = players.get_mut(trigger.target()).unwrap();
actions
.bind::<Move>()
.to(Cardinal::wasd_keys())
Expand All @@ -69,12 +69,12 @@ fn car_binding(trigger: Trigger<Binding<InCar>>, mut players: Query<&mut Actions
}

fn apply_movement(trigger: Trigger<Fired<Move>>, mut players: Query<&mut Transform>) {
let mut transform = players.get_mut(trigger.entity()).unwrap();
let mut transform = players.get_mut(trigger.target()).unwrap();
transform.translation += trigger.value.extend(0.0);
}

fn rotate(trigger: Trigger<Started<Rotate>>, mut players: Query<&mut Transform>) {
let mut transform = players.get_mut(trigger.entity()).unwrap();
let mut transform = players.get_mut(trigger.target()).unwrap();
transform.rotate_z(FRAC_PI_4);
}

Expand All @@ -84,11 +84,11 @@ fn enter_car(
mut players: Query<&mut PlayerColor>,
) {
// Change color for visibility.
let mut color = players.get_mut(trigger.entity()).unwrap();
let mut color = players.get_mut(trigger.target()).unwrap();
**color = FUCHSIA_400.into();

commands
.entity(trigger.entity())
.entity(trigger.target())
.remove::<Actions<OnFoot>>()
.insert(Actions::<InCar>::default());
}
Expand All @@ -98,11 +98,11 @@ fn exit_car(
mut commands: Commands,
mut players: Query<&mut PlayerColor>,
) {
let mut color = players.get_mut(trigger.entity()).unwrap();
let mut color = players.get_mut(trigger.target()).unwrap();
**color = Default::default();

commands
.entity(trigger.entity())
.entity(trigger.target())
.remove::<Actions<InCar>>()
.insert(Actions::<OnFoot>::default());
}
Expand Down
48 changes: 23 additions & 25 deletions examples/keybinding_menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,8 @@ impl Plugin for KeybindingMenuPlugin {
(
update_button_text,
(
cancel_binding
.never_param_warn()
.run_if(input_just_pressed(KeyCode::Escape)),
bind.never_param_warn(),
cancel_binding.run_if(input_just_pressed(KeyCode::Escape)),
bind,
)
.chain(),
),
Expand Down Expand Up @@ -62,11 +60,11 @@ fn setup(mut commands: Commands) {

// We use separate root node to let dialogs cover the whole UI.
commands
.spawn((Node {
.spawn(Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
..Default::default()
},))
})
.with_children(|parent| {
parent
.spawn(Node {
Expand Down Expand Up @@ -124,7 +122,7 @@ struct SettingsField(&'static str);
/// Number of input columns.
const INPUTS_PER_ACTION: usize = 3;

fn setup_actions(parent: &mut ChildBuilder, settings: &KeyboardSettings) -> Entity {
fn setup_actions(parent: &mut ChildSpawnerCommands, settings: &KeyboardSettings) -> Entity {
parent
.spawn(Node {
display: Display::Grid,
Expand Down Expand Up @@ -172,7 +170,7 @@ fn setup_actions(parent: &mut ChildBuilder, settings: &KeyboardSettings) -> Enti
}

fn setup_action_row(
parent: &mut ChildBuilder,
parent: &mut ChildSpawnerCommands,
name: &'static str,
inputs: &[Input],
field: SettingsField,
Expand Down Expand Up @@ -210,7 +208,7 @@ fn delete_binding(
mut input_buttons: Query<(&Name, &mut InputButton)>,
delete_buttons: Query<&DeleteButton>,
) {
let delete_button = delete_buttons.get(trigger.entity()).unwrap();
let delete_button = delete_buttons.get(trigger.target()).unwrap();
let (name, mut input_button) = input_buttons
.get_mut(delete_button.button_entity)
.expect("delete button should point to an input button");
Expand All @@ -221,16 +219,16 @@ fn delete_binding(
fn show_binding_dialog(
trigger: Trigger<Pointer<Click>>,
mut commands: Commands,
root_entity: Single<Entity, (With<Node>, Without<Parent>)>,
root_entity: Single<Entity, (With<Node>, Without<ChildOf>)>,
names: Query<&Name>,
) {
let name = names.get(trigger.entity()).unwrap();
let name = names.get(trigger.target()).unwrap();
info!("starting binding for '{name}'");

commands.entity(*root_entity).with_children(|parent| {
parent
.spawn(BindingDialog {
button_entity: trigger.entity(),
button_entity: trigger.target(),
})
.with_children(|parent| {
parent
Expand Down Expand Up @@ -264,7 +262,7 @@ fn bind(
mut key_events: EventReader<KeyboardInput>,
mut mouse_button_events: EventReader<MouseButtonInput>,
dialog: Single<(Entity, &BindingDialog)>,
root_entity: Single<Entity, (With<Node>, Without<Parent>)>,
root_entity: Single<Entity, (With<Node>, Without<ChildOf>)>,
mut buttons: Query<(Entity, &Name, &mut InputButton)>,
) {
let keys = key_events
Expand Down Expand Up @@ -337,12 +335,12 @@ fn bind(
button.input = Some(input);
}

commands.entity(dialog_entity).despawn_recursive();
commands.entity(dialog_entity).despawn();
}

fn cancel_binding(mut commands: Commands, dialog_entity: Single<Entity, With<BindingDialog>>) {
info!("cancelling binding");
commands.entity(*dialog_entity).despawn_recursive();
commands.entity(*dialog_entity).despawn();
}

fn replace_binding(
Expand All @@ -364,7 +362,7 @@ fn replace_binding(
button.input = input;

info!("reassigning binding to '{name}'");
commands.entity(dialog_entity).despawn_recursive();
commands.entity(dialog_entity).despawn();
}

fn cancel_replace_binding(
Expand All @@ -373,7 +371,7 @@ fn cancel_replace_binding(
dialog_entity: Single<Entity, With<ConflictDialog>>,
) {
info!("cancelling replace binding");
commands.entity(*dialog_entity).despawn_recursive();
commands.entity(*dialog_entity).despawn();
}

fn apply(
Expand Down Expand Up @@ -432,13 +430,13 @@ fn update_button_background(
#[derive(Component, Default)]
#[require(
Button,
Node(|| Node {
Node {
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
width: Val::Px(160.0),
height: Val::Px(35.0),
..Default::default()
}),
},
)]
struct SettingsButton;

Expand All @@ -454,13 +452,13 @@ struct InputButton {
#[derive(Component)]
#[require(
Button,
Node(|| Node {
Node {
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
width: Val::Px(35.0),
height: Val::Px(35.0),
..Default::default()
}),
},
)]
struct DeleteButton {
/// Entity with [`InputButton`].
Expand All @@ -469,16 +467,16 @@ struct DeleteButton {

#[derive(Component, Default)]
#[require(
Node(|| Node {
Node {
position_type: PositionType::Absolute,
width: Val::Percent(100.0),
height: Val::Percent(100.0),
align_items: AlignItems::Center,
justify_content: JustifyContent::Center,
..Default::default()
}),
FocusPolicy(|| FocusPolicy::Block),
BackgroundColor(|| BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.3))),
},
FocusPolicy::Block,
BackgroundColor(Color::srgba(1.0, 1.0, 1.0, 0.3)),
)]
struct Dialog;

Expand Down
Loading
Loading