diff --git a/TODO.md b/TODO.md index ce85433..38636a4 100644 --- a/TODO.md +++ b/TODO.md @@ -1,15 +1,15 @@ # v0.1.0 --[x] contracts - -[x] loby - -[x] actions - -[x] game state --[ ] way to define default controlls --[ ] layers for controlls: if on (shift + space) action enable, ignore on (space) action --[ ] warnings on actions collision --[ ] basic example +- [x] contracts + - [x] loby + - [x] actions + - [x] game state +- [x] way to define default controlls +- [ ] layers for controlls: if on (shift + space) action enable, ignore on (space) action +- [ ] warnings on actions collision +- [ ] basic example # v0.2.0 --[ ] layers for controlls: user posibility give priority to controls --[ ] controller support --[ ] touch pad support --[ ] posibility support more that one game state +- [ ] layers for controlls: user posibility give priority to controls +- [ ] controller support +- [ ] touch pad support +- [ ] posibility support more that one game state diff --git a/crate/bevy_controls/example/basic/src/main.rs b/crate/bevy_controls/example/basic/src/main.rs index e80c97e..5cc107e 100644 --- a/crate/bevy_controls/example/basic/src/main.rs +++ b/crate/bevy_controls/example/basic/src/main.rs @@ -66,87 +66,82 @@ fn main() { }), ..default() }), - ControlsPlugin::::default(), + ControlsPlugin::::new( + Controls::::new() + .with( + MyAction::Left, + // this way input will work only on latin layout only on `A` + 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 + Binding::new(ButtonCombination::Single(InputType::Keyboard( + Keyboard::ScanCode(ScanCode(35)), + ))), + ) + .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)), + ))), + ) + .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)), + ))), + ) + .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)), + ))), + ) + .with( + MyAction::Up, + Binding::new(ButtonCombination::Single(InputType::Keyboard( + Keyboard::KeyCode(KeyCode::Space), + ))), + ) + .with( + MyAction::Down, + Binding::new(ButtonCombination::Chord(vec![ + InputType::Keyboard(Keyboard::KeyCode(KeyCode::ShiftLeft)), + InputType::Keyboard(Keyboard::KeyCode(KeyCode::Space)), + ])), + ) + .build(), + ), )) .insert_resource(ClearColor(Color::NONE)) .init_resource::() - .add_systems(Startup, (add_bindings, setup)) + .add_systems(Startup, setup) .add_systems(Update, text_update_system) .run(); } -// TODO: default bingings... -fn add_bindings(mut controls: ResMut>) { - controls.force_push( - MyAction::Left, - // this way input will work only on latin layout only on `A` - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::KeyCode(KeyCode::A), - ))), - ); - controls.force_push( - MyAction::Left, - // this way input will work only on any layout on same button, 35 is `H` for `us` layout or - // `О` for `ru` layout - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::ScanCode(ScanCode(35)), - ))), - ); - - controls.force_push( - MyAction::Back, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::KeyCode(KeyCode::S), - ))), - ); - controls.force_push( - MyAction::Back, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::ScanCode(ScanCode(36)), - ))), - ); - - controls.force_push( - MyAction::Forward, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::KeyCode(KeyCode::W), - ))), - ); - controls.force_push( - MyAction::Forward, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::ScanCode(ScanCode(37)), - ))), - ); - - controls.force_push( - MyAction::Right, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::KeyCode(KeyCode::D), - ))), - ); - controls.force_push( - MyAction::Right, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::ScanCode(ScanCode(38)), - ))), - ); - - controls.force_push( - MyAction::Up, - Binding::new(ButtonCombination::Single(InputType::Keyboard( - Keyboard::KeyCode(KeyCode::Space), - ))), - ); - controls.force_push( - MyAction::Down, - Binding::new(ButtonCombination::Chord(vec![ - InputType::Keyboard(Keyboard::KeyCode(KeyCode::ShiftLeft)), - InputType::Keyboard(Keyboard::KeyCode(KeyCode::Space)), - ])), - ); -} - #[derive(Component)] struct TextBlock; @@ -158,7 +153,7 @@ fn setup(mut commands: Commands) { commands.spawn(( TextBundle::from_sections([ TextSection::new( - "Action: ", + "Info: this example is intended to show basic crate capabilities and limitations\nso WASD work only on US layout, but HJKL may work on any layout\nAction: ", TextStyle { font_size: TEXT_SIZE, ..default() diff --git a/crate/bevy_controls/src/plugin.rs b/crate/bevy_controls/src/plugin.rs index 21d0157..fbe87c7 100644 --- a/crate/bevy_controls/src/plugin.rs +++ b/crate/bevy_controls/src/plugin.rs @@ -14,26 +14,40 @@ use crate::{ resource::*, }; -pub struct ControlsPlugin { +pub struct ControlsPlugin, Gs: GameState> { _action: std::marker::PhantomData, _inputs_container: std::marker::PhantomData, _game_state: std::marker::PhantomData, + controls: Controls, } -impl Default for ControlsPlugin { +impl, Gs: GameState> Default for ControlsPlugin { fn default() -> Self { Self { _action: std::marker::PhantomData, _inputs_container: std::marker::PhantomData, _game_state: std::marker::PhantomData, + controls: Controls::::default(), } } } +impl, Gs: GameState> ControlsPlugin { + pub fn new(controls: Controls) -> Self { + Self { + _action: std::marker::PhantomData, + _inputs_container: std::marker::PhantomData, + _game_state: std::marker::PhantomData, + controls, + } + } +} + + impl, Gs: GameState> Plugin for ControlsPlugin { fn build(&self, app: &mut App) { app - .init_resource::>() + .insert_resource(self.controls.clone()) .init_resource::() .add_state::() .add_systems(Update, Self::save_input); @@ -53,9 +67,11 @@ impl, Gs: GameState> ControlsPlugin controls: Res>, game_state: Res>, ) { + // get current client inputs if let Some(inputs) = inputs_container.me_mut() { for (action, config) in controls.iter() { 'bindings_loop: for binding in config.bindings.iter() { + // check binding conditions for condition in &binding.conditions { match condition { BindingCondition::InGameState(state) => { @@ -68,16 +84,15 @@ impl, Gs: GameState> ControlsPlugin log::trace!("action binding {:?} {:?} in condition", action, binding); + // check inputs & mark actions match &binding.input { ButtonCombination::Single(button) => match button { InputType::Keyboard(Keyboard::KeyCode(key)) => { - log::trace!("presed?: {:?}", keyboard_input_keycode.pressed(*key)); - log::trace!("active"); if keyboard_input_keycode.pressed(*key) { inputs.forced_set(*action, true); break; // when on binding trigered no sence check another } - inputs.forced_set(*action, false); // FIXME: this is happening on every pass so too frequently + inputs.forced_set(*action, false); // FIXME: this is happening on every pass so maybe too frequently } InputType::Keyboard(Keyboard::ScanCode(code)) => { log::trace!("presed?: {:?}", keyboard_input_scancode.pressed(*code)); @@ -86,7 +101,7 @@ impl, Gs: GameState> ControlsPlugin inputs.forced_set(*action, true); break; // when on binding trigered no sence check another } - inputs.forced_set(*action, false); // FIXME: this is happening on every pass so too frequently + inputs.forced_set(*action, false); // FIXME: this is happening on every pass so maybe too frequently } InputType::Mouse(input) => match input { MouseInput::Axis(_axis) => { diff --git a/crate/bevy_controls/src/resource.rs b/crate/bevy_controls/src/resource.rs index 57f75ae..4abf146 100644 --- a/crate/bevy_controls/src/resource.rs +++ b/crate/bevy_controls/src/resource.rs @@ -503,9 +503,29 @@ impl BindingConfig { } } +#[derive(Deref, DerefMut)] +pub struct ControlsBuilder(Controls); + +impl ControlsBuilder{ + /// + pub fn with(mut self, action: A, binding: Binding) -> Self { + self.force_push(action, binding); + self + } + + /// + pub fn build(mut self) -> Controls { + // If you see this error, you may add new action in menu_actions + // or make sure that you have only one Menufor<'a> Action<'a> with the same name in the Menufor<'a> Action<'a>s + assert!(validate_hash_map(&**self)); + + std::mem::take(&mut self) + } +} + common_traits_conditions! { /// Contains all bindings for actions - #[derive(Resource, Clone)] + #[derive(Resource, Clone, Deref, DerefMut)] #[cfg_attr(feature = "reflect", reflect(Resource))] // TODO: Add delay for input pub struct Controls( @@ -533,6 +553,11 @@ impl Default for Controls { } impl Controls { + /// New [`Controls`] instance + pub fn new() -> ControlsBuilder { + ControlsBuilder(Controls(HashMap::new())) + } + /// Returns bindings for action pub fn get(&self, action: A) -> Option<&BindingConfig> { self.0.get(&action) diff --git a/index.html b/index.html index b8ab208..5fb1e65 100644 --- a/index.html +++ b/index.html @@ -1,3 +1,28 @@ -
    -
  • [ ]
  • +

    v0.1.0

    +
      +
    • +
        +
      • +
      • +
      • +
    • +
    • +
    • +
    • +
    • +
    +

    v0.2.0

    +
      +
    • +
    • +
    • +