1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use bevy::prelude::*;
use bevy_input_bindings::prelude::*;
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
// Add the keyboard plugin attached to the custom binder
keyboard::Plugin::<MyActions, MyValues, MyKeyboardBinding>::new(),
))
// Add observers to print the inputs. It will catch events for the `MyActions` actions,
// find the `ControllerInterface` that sent it, and print the event data.
// The first observer use the entities stored in the action event to find the players.
.add_observer(|action: On<ActionEvent<MyActions>>, players: Query<&Name, With<Player>>| {
// Iterate over the controlled entities
for controlled_id in action.controlling() {
// Get the player name from the entity stored
let Ok(player_name) = players.get(*controlled_id) else {
continue;
};
// Print data about this action
println!("[OBS1] Player {}: {:?}", player_name.as_str(), action.key());
}
})
// The second observer use the `ControlledBy` component of player and compare it to the
// controller id stored in the action event.
.add_observer(
|action: On<ActionEvent<MyActions>>,
players: Query<(&Name, &ControlledBy), With<Player>>| {
for (name, controlled_by) in players {
// Act only on the controlled players
if controlled_by.controller() != action.controller() {
continue;
}
// Print data about this action
println!("[OBS2] Player {}: {:?}", name.as_str(), action.key(),);
}
},
)
// Add a startup system to initiate the entities
.add_systems(Startup, |mut commands: Commands| {
commands.spawn(Camera3d::default());
// Instantiate the controller and keep the id
let controller_id = commands.spawn(MyKeyboardBinding::new()).id();
// Instantiate the player with a `ControlledBy` component to link it to the controller.
// This will also add a `Controlling` component to the controller, just like any Bevy
// relationships.
commands.spawn((Player, Name::new("Player1"), ControlledBy(controller_id)));
// Instantiate another player controlled
commands.spawn((Player, Name::new("Player2"), ControlledBy(controller_id)));
// Instantiate another player not controlled
commands.spawn((Player, Name::new("Player3")));
})
// Log the values by using the `Controlling` component of controller to know to with player
// applying the
.add_systems(
Update,
|controllers: Query<(&ControllerValues<MyValues>, &Controlling)>,
players: Query<&Name, With<Player>>| {
for (value, controlling) in controllers {
// Only log the 2 axis values
let Some(bool_value) = value.get_as_bool(&MyValues::Jumping) else {
continue;
};
// Log only if true
if !bool_value {
continue;
}
// Iterate over the controlled players
for player_id in controlling.controlling() {
let Ok(player_name) = players.get(*player_id) else {
continue;
};
println!("{} jumping", player_name);
}
}
},
)
.run();
}
#[derive(Component)]
struct Player;
/// Custom actions for this example
#[derive(Debug)]
enum MyActions {
Jump,
}
/// Custom values for this example
#[derive(Debug, Hash, PartialEq, Eq)]
enum MyValues {
Jumping,
}
/// Custom binder for this example
#[derive(Component, Reflect)]
struct MyKeyboardBinding {
jump: keyboard::triggers::ButtonPressed,
jumping: keyboard::values::ButtonPressed,
}
impl MyKeyboardBinding {
/// Create a keyboard binder
fn new() -> Self {
Self {
jump: keyboard::triggers::ButtonPressed::new(KeyCode::KeyQ),
jumping: keyboard::values::ButtonPressed::new(KeyCode::KeyW),
}
}
}
impl keyboard::Binding<MyActions, MyValues> for MyKeyboardBinding {
fn get_action_bindings<'a>(
&'a mut self,
) -> Vec<(&'a mut dyn keyboard::TriggerTrait, MyActions)> {
return vec![(&mut self.jump, MyActions::Jump)];
}
fn get_value_bindings<'a>(
&'a mut self,
) -> Vec<(&'a mut dyn keyboard::FunctionTrait, MyValues)> {
return vec![(&mut self.jumping, MyValues::Jumping)];
}
}