Skip to content

Devlyn-Nelson/inlet

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Input library for Bevy Game Engine.

Features

  • Uses bevy_input internally, supports Keyboard, Gamepad, and Mouse.
  • Uses any Hash + Eq type for keying input types.
  • Can produce Message's for common input events.
  • InputBinding lets you bind any axis or button to any axis or button like input.
    • ActionBinding has internal states to best represent button like behavior: JustPressed, Pressed, JustReleased, Released. Can also be used as digital (-1, 0, 1) axis.
    • ValueBinding can return a value (-1.0 to 1.0) from any axis or set of buttons. Can have a stack of generic functions that modify the output. Can be used as a button, by default it is assumed any non-zero value is pressed, but modifiers can enable you to control this behavior more finely.
    • DualValueBinding internally behaves as if it is just 2 ValueBinding's.

Usage

see examples/demo.rs for a more complete control scheme.

Poll Only

Create a list of input bindings to be used as a key to register bindings and retrieve values.

This type MUST implement Hash + PartialEq + Eq

#[derive(Hash, PartialEq, Eq)]
enum InputTypes {
    Move,
    Zoom,
    Jump,
}

Create a Bindings component and add it to your entity.

SimpleInputBindings is just a type definition that fills in the message type with a placeholder for when you don't want to deal with both generic types required for InputBindings.

SimpleInputBindings::<InputTypes>::new()
    .with_action_binding(
        InputTypes::Jump,
        vec![KeyCode::Space.into(), GamepadButton::South.into()].into(),
    )
    .with_value_binding(
        InputTypes::Zoom,
        AxisBinding::mouse_y_scroll().invert().into(),
    )
    .with_dual_value_binding(
        InputTypes::Move,
        (
            vec![
                AxisBinding::keyboard_da(),
                AxisBinding::gamepad_left_stick_x(),
                AxisBinding::gamepad_dpad_right_left(),
            ],
            vec![
                AxisBinding::keyboard_ws(),
                AxisBinding::gamepad_left_stick_y(),
                AxisBinding::gamepad_dpad_up_down(),
            ],
        )
            .into(),
    );

Make a system that uses the values from bindings

fn control_player(
    time: Res<Time>,
    mut player: Single<(&mut Transform, &SimpleInputBindings<InputTypes>)>,
    mut camera: Single<
        &mut Transform,
        (With<Camera3d>, Without<SimpleInputBindings<InputTypes>>),
    >,
) {
    let delta_time = time.delta_secs();
    let mover = player.1.get_dual_value(&InputTypes::Move);
    let y_scale = player.0.scale.y * 0.5;
    let mover = Vec3::new(
        mover.x,
        if player.1.get_action_state(&InputTypes::Jump).just_pressed() {
            10.0 * y_scale
        } else {
            0.0
        },
        mover.y,
    );
    player.0.translation += mover * delta_time;
    let zoom = 1.0 + (player.1.get_value(&InputTypes::Zoom) * delta_time);
    camera.translation *= zoom;
}

Add SimpleInputManagementPlugin<InputTypes>::default() and your system to your bevy app.

SimpleInputManagementPlugin is just a type definition that fills in the message type with a placeholder type for when you don't want to deal with both generic types required for InputManagementPlugin.

Message Based

Create a list of input bindings to be used as a key to register bindings and retrieve values.

This type MUST implement Hash + PartialEq + Eq

Also create a type that implements Message

You can make only 1 type that gets used for both if you want. This example separates them simply to show they can be separate types for cases where you are mixing Message-Based and Polling-Based bindings.

#[derive(Hash, PartialEq, Eq)]
enum InputTypes {
    Grow,
    Shrink,
}

#[derive(Message)]
enum MessageType {
    Grow,
    Shrink,
}

// These functions are for giving to the bindings to create the messages.
impl MessageType {
    pub fn grow() -> Self {
        Self::Grow
    }
    pub fn shrink() -> Self {
        Self::Shrink
    }
}

Create a Bindings component and add it to your entity.

InputBindings::<InputTypes, MessageType>::new()
    .with_action_binding(
        InputTypes::Grow,
        (
            vec![
                // W -> S -> D -> A
                ButtonCombo::new(vec![
                    KeyCode::KeyW.into(),
                    KeyCode::KeyS.into(),
                    KeyCode::KeyD.into(),
                    KeyCode::KeyA.into(),
                ])
                .into(),
                // Up -> Down -> Right -> Left on dpad
                ButtonCombo::new(vec![
                    GamepadButton::DPadUp.into(),
                    GamepadButton::DPadDown.into(),
                    GamepadButton::DPadRight.into(),
                    GamepadButton::DPadLeft.into(),
                ])
                .into(),
            ],
            ButtonEventBinding::WhenPressed(MessageType::grow),
        )
            .into(),
    )
    .with_action_binding(
        InputTypes::Shrink,
        (
            vec![
                ButtonChord::new(vec![
                    KeyCode::KeyW.into(),
                    KeyCode::KeyS.into(),
                    KeyCode::KeyA.into(),
                    KeyCode::KeyD.into(),
                ])
                .into(),
                ButtonChord::new(vec![
                    GamepadButton::DPadUp.into(),
                    GamepadButton::DPadDown.into(),
                    GamepadButton::DPadLeft.into(),
                    GamepadButton::DPadRight.into(),
                ])
                .into(),
            ],
            ButtonEventBinding::WhenPressed(MessageType::shrink),
        )
            .into(),
    );

Make a system that uses the values from bindings

you can also use polling in this system or other systems if you would like.

fn accept_events(
    mut messages: MessageReader<MessageType>,
    mut player: Single<&mut Transform, With<InputBindings<InputTypes, MessageType>>>,
) {
    for message in messages.read() {
        match cheat {
            MessageType::Grow => player.scale += 1.,
            MessageType::Shrink => player.scale -= 1.,
        }
    }
}

Add InputManagementPlugin<InputTypes, MessageType>::default() and your system to your bevy app.

In Progress

  • Interrupting Combos when an invalid button is pressed, with setting to disable interrupts.
  • Better Clash Detection.

About

Bevy Input Mananger

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages