bevy_controls 1.0.0

Bevy controls library
Documentation
use bevy::prelude::*;
use bevy_controls::{
    analog::{
        analog_action_reader::AnalogActionReader, analog_control::AnalogControl,
        analog_inputs::AnalogInputs,
    },
    button::{
        button_action_reader::ButtonActionReader, button_control::ButtonControl, buttons::Buttons,
    },
    controls_plugin::ControlsPlugin,
};
use bevy_inspector_egui::{bevy_egui::EguiPlugin, quick::WorldInspectorPlugin};

#[derive(Debug, Clone, Eq, PartialEq, Hash, Default, States, Reflect)]
enum ControlContext {
    #[default]
    MainMenu,
    Game,
    OpenInventory,
    Paused,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Reflect)]
enum ControlAction {
    Test1,
    TestAnalog1,
    TestMovementX,
    TestMovementY,
}

fn main() {
    App::new()
        .register_type::<ButtonControl<ControlContext, ControlAction>>()
        .register_type::<AnalogControl<ControlContext, ControlAction>>()
        .add_plugins((
            DefaultPlugins,
            EguiPlugin::default(),
            WorldInspectorPlugin::new(),
            ControlsPlugin::<ControlContext, ControlAction>::default(),
        ))
        .add_systems(Startup, setup)
        .add_systems(Update, (update_state, update))
        .run();
}

fn update(
    mut controls: Query<&mut ButtonControl<ControlContext, ControlAction>>,
    analog_controls: Query<&AnalogControl<ControlContext, ControlAction>>,
) {
    if controls.action_just_pressed(ControlAction::Test1) {
        info!("Executed TEST Action!");
    }

    if let Some(test_analog) = analog_controls.read_action(ControlAction::TestAnalog1) {
        info!("Test analog value: {}", test_analog);
    }

    if let Some(move_x) = analog_controls.read_action(ControlAction::TestMovementX)
        && let Some(move_y) = analog_controls.read_action(ControlAction::TestMovementY)
    {
        let mut movement = Vec2::new(move_x, move_y);
        if movement.length() > 1. {
            movement = movement.normalize_or_zero();
        }

        info!("Test Movement: {}", movement);
    }
}

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d);

    commands.spawn((
        Name::new("Test1 Control"),
        ButtonControl::new(
            ControlAction::Test1,
            vec![ControlContext::MainMenu],
            vec![
                Buttons::Keyboard(KeyCode::Enter),
                Buttons::Mouse(MouseButton::Left),
                Buttons::Gamepad(GamepadButton::North),
            ],
        ),
    ));

    commands.spawn((
        Name::new("TestAnalog1 Control"),
        AnalogControl::new(
            ControlAction::TestAnalog1,
            vec![ControlContext::Paused],
            vec![
                AnalogInputs::Gamepad(GamepadButton::RightTrigger2),
                AnalogInputs::Button(Buttons::Gamepad(GamepadButton::North), 1.),
                AnalogInputs::Button(Buttons::Gamepad(GamepadButton::South), -1.),
            ],
        ),
    ));

    commands.spawn((
        Name::new("Test Movement X"),
        AnalogControl::new(
            ControlAction::TestMovementX,
            vec![ControlContext::Game, ControlContext::OpenInventory],
            vec![
                AnalogInputs::GamepadAxis(GamepadAxis::LeftStickX),
                AnalogInputs::Button(Buttons::Keyboard(KeyCode::KeyA), -1.),
                AnalogInputs::Button(Buttons::Keyboard(KeyCode::KeyD), 1.),
            ],
        ),
    ));

    commands.spawn((
        Name::new("Test Movement Y"),
        AnalogControl::new(
            ControlAction::TestMovementY,
            vec![ControlContext::Game, ControlContext::OpenInventory],
            vec![
                AnalogInputs::GamepadAxis(GamepadAxis::LeftStickY),
                AnalogInputs::Button(Buttons::Keyboard(KeyCode::KeyS), -1.),
                AnalogInputs::Button(Buttons::Keyboard(KeyCode::KeyW), 1.),
            ],
        ),
    ));
}

fn update_state(
    context: Res<State<ControlContext>>,
    mut next_context: ResMut<NextState<ControlContext>>,
    input: Res<ButtonInput<KeyCode>>,
) {
    if !input.just_pressed(KeyCode::Space) {
        return;
    }

    let next_state = match context.get() {
        ControlContext::MainMenu => ControlContext::Game,
        ControlContext::Game => ControlContext::OpenInventory,
        ControlContext::OpenInventory => ControlContext::Paused,
        ControlContext::Paused => ControlContext::MainMenu,
    };

    next_context.set(next_state);
}