feat: possibility define BindConfig in plugin setup
This commit is contained in:
@@ -9,7 +9,10 @@ use bevy::{ecs::schedule::States, prelude::*};
|
||||
use bevy_controls::{
|
||||
contract::InputsContainer,
|
||||
plugin::ControlsPlugin,
|
||||
resource::{Binding, ButtonCombination, Controls, InputType, InputValue, Keyboard, PlayerInputs},
|
||||
resource::{
|
||||
ActivationOptions, Binding, BindingConfig, Bindings, ButtonCombination, Controls, InputType,
|
||||
InputValue, Keyboard, OptionsMode, PlayerInputs,
|
||||
},
|
||||
};
|
||||
use bevy_controls_derive::{Action, GameState};
|
||||
use strum_macros::EnumIter;
|
||||
@@ -68,68 +71,54 @@ fn main() {
|
||||
}),
|
||||
ControlsPlugin::<MyAction, MyInputsContainer, MyGameState>::new(
|
||||
Controls::<MyAction, MyGameState>::new()
|
||||
// the first control instance I will describe in detail
|
||||
.with(
|
||||
MyAction::Left,
|
||||
// this way input will work only on latin layout only on `A`
|
||||
BindingConfig::new(Bindings::new(vec![
|
||||
// this way input will work only on latin layout only on `A`, because it uses `Keyboard::KeyCode`
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::A),
|
||||
))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Left,
|
||||
// this way input will work only on any layout on same button, 35 is `H` for `us` layout or
|
||||
// `О` for `ru` layout
|
||||
// `О` for `ru` layout, because it uses `Keyboard::ScanCode`
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::ScanCode(ScanCode(35)),
|
||||
))),
|
||||
])),
|
||||
)
|
||||
// the rest will be simplified
|
||||
.with(
|
||||
MyAction::Back,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::S),
|
||||
))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Back,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::ScanCode(ScanCode(36)),
|
||||
))),
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::S)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(36))),
|
||||
]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Forward,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::W),
|
||||
))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Forward,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::ScanCode(ScanCode(37)),
|
||||
))),
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::W)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(37))),
|
||||
]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Right,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::D),
|
||||
))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Right,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::ScanCode(ScanCode(38)),
|
||||
))),
|
||||
BindingConfig::from_vec(vec![
|
||||
Binding::from_single(InputType::from_key_code(KeyCode::D)),
|
||||
Binding::from_single(InputType::from_scan_code(ScanCode(38))),
|
||||
]),
|
||||
)
|
||||
.with(
|
||||
MyAction::Up,
|
||||
Binding::new(ButtonCombination::Single(InputType::Keyboard(
|
||||
Keyboard::KeyCode(KeyCode::Space),
|
||||
BindingConfig::from_bind(Binding::from_single(InputType::from_key_code(
|
||||
KeyCode::Space,
|
||||
))),
|
||||
)
|
||||
.with(
|
||||
MyAction::Down,
|
||||
Binding::new(ButtonCombination::Chord(vec![
|
||||
InputType::Keyboard(Keyboard::KeyCode(KeyCode::ShiftLeft)),
|
||||
InputType::Keyboard(Keyboard::KeyCode(KeyCode::Space)),
|
||||
BindingConfig::from_bind(Binding::from_chord(vec![
|
||||
InputType::from_key_code(KeyCode::ShiftLeft),
|
||||
InputType::from_key_code(KeyCode::Space),
|
||||
])),
|
||||
)
|
||||
.build(),
|
||||
|
||||
@@ -207,7 +207,18 @@ common_traits_conditions! {
|
||||
// TODO: Gamepad(GamepadButtonType),
|
||||
// TODO: Touch screen
|
||||
}
|
||||
}
|
||||
|
||||
impl InputType {
|
||||
pub fn from_key_code(key_code: KeyCode) -> Self {
|
||||
InputType::Keyboard(Keyboard::KeyCode(key_code))
|
||||
}
|
||||
pub fn from_scan_code(scan_code: ScanCode) -> Self {
|
||||
InputType::Keyboard(Keyboard::ScanCode(scan_code))
|
||||
}
|
||||
}
|
||||
|
||||
common_traits_conditions! {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Keyboard {
|
||||
KeyCode(KeyCode),
|
||||
@@ -231,16 +242,19 @@ common_traits_conditions! {
|
||||
}
|
||||
|
||||
/// Represents a binding that can be changed by the player
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// default: [`Immutable`](OptionsMode::Immutable)
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub enum OptionsMode {
|
||||
/// Represents a binding that cannot be changed as it is crucial to the game logic
|
||||
#[default] // I think this is more safe
|
||||
Immutable,
|
||||
/// Represents a binding that the player can customize
|
||||
Customizable,
|
||||
}
|
||||
|
||||
/// Represents the manner in which input is registered
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// default: [`Tap`](ActivationMode::Tap)
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub enum ActivationMode {
|
||||
/// for<'a> Action<'a> is triggered when the button is pressed
|
||||
Hold,
|
||||
@@ -248,6 +262,7 @@ common_traits_conditions! {
|
||||
/// and cannot be triggered again until the button is released
|
||||
/// you don't need to release all buttons in chord
|
||||
/// you can release only last pressed button
|
||||
#[default] // I think this is more safe
|
||||
Tap,
|
||||
}
|
||||
|
||||
@@ -265,8 +280,8 @@ common_traits_conditions! {
|
||||
impl Default for ActivationOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: ActivationMode::Tap, // Because it is more safe
|
||||
option: OptionsMode::Immutable,
|
||||
mode: ActivationMode::default(),
|
||||
option: OptionsMode::default(),
|
||||
delay: 0.05, // 20 times per second; 14 - world record?
|
||||
}
|
||||
}
|
||||
@@ -331,6 +346,20 @@ impl<Gs: GameState> Binding<Gs> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_single(input: InputType) -> Self {
|
||||
Self {
|
||||
input: ButtonCombination::Single(input),
|
||||
conditions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_chord(input: Vec<InputType>) -> Self {
|
||||
Self {
|
||||
input: ButtonCombination::Chord(input),
|
||||
conditions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_condition(mut self, condition: BindingCondition<Gs>) -> Self {
|
||||
self.conditions.push(condition);
|
||||
self
|
||||
@@ -415,19 +444,24 @@ impl<Gs: GameState> Default for Bindings<Gs> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
list: Vec::new(),
|
||||
options: OptionsMode::Immutable,
|
||||
options: OptionsMode::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Gs: GameState> Bindings<Gs> {
|
||||
pub fn new(bindings: Vec<Binding<Gs>>, options: OptionsMode) -> Self {
|
||||
pub fn new(bindings: Vec<Binding<Gs>>) -> Self {
|
||||
Self {
|
||||
list: bindings,
|
||||
options,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_option_mode(mut self, options: OptionsMode) -> Self {
|
||||
self.options = options;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn force_push(&mut self, binding: Binding<Gs>) {
|
||||
self.list.push(binding);
|
||||
}
|
||||
@@ -495,21 +529,40 @@ common_traits_conditions! {
|
||||
}
|
||||
|
||||
impl<Gs: GameState> BindingConfig<Gs> {
|
||||
pub fn new(bindings: Bindings<Gs>, activation: ActivationOptions) -> Self {
|
||||
pub fn new(bindings: Bindings<Gs>) -> Self {
|
||||
Self {
|
||||
bindings,
|
||||
activation,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_vec(bindings: Vec<Binding<Gs>>) -> Self {
|
||||
Self {
|
||||
bindings: Bindings::new(bindings),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_bind(binding: Binding<Gs>) -> Self {
|
||||
Self {
|
||||
bindings: Bindings::new(vec![binding]),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_activation_options(mut self, activation: ActivationOptions) -> Self {
|
||||
self.activation = activation;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
pub struct ControlsBuilder<A: Action, Gs: GameState>(Controls<A, Gs>);
|
||||
|
||||
impl<A: Action, Gs: GameState> ControlsBuilder<A, Gs>{
|
||||
impl<A: Action, Gs: GameState> ControlsBuilder<A, Gs> {
|
||||
///
|
||||
pub fn with(mut self, action: A, binding: Binding<Gs>) -> Self {
|
||||
self.force_push(action, binding);
|
||||
pub fn with(mut self, action: A, config: BindingConfig<Gs>) -> Self {
|
||||
self.insert(action, config);
|
||||
self
|
||||
}
|
||||
|
||||
@@ -527,10 +580,9 @@ common_traits_conditions! {
|
||||
/// Contains all bindings for actions
|
||||
#[derive(Resource, Clone, Deref, DerefMut)]
|
||||
#[cfg_attr(feature = "reflect", reflect(Resource))]
|
||||
// TODO: Add delay for input
|
||||
pub struct Controls<A: Action, Gs: GameState>(
|
||||
#[cfg_attr(feature = "serialize", serde(bound(deserialize = "")))]
|
||||
// TODO: change HashMap to Vec for faster iteration
|
||||
// FIXME: change HashMap to Vec for faster iteration
|
||||
HashMap<A, BindingConfig<Gs>>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user