Skip to main content

Crate cloudiful_bevy_input

Crate cloudiful_bevy_input 

Source
Expand description

§cloudiful-bevy-input

Reusable Bevy input abstraction for game-defined actions.

§What it provides

  • InputBindingsPlugin<A>: generic plugin for a game-defined action enum
  • InputMap<A>: action -> keyboard/gamepad bindings
  • ActionState<A>: pressed, just_pressed, just_released, and analog value
  • PrimaryGamepad: auto or manual primary gamepad selection
  • ActiveInputDevice: tracks whether keyboard/mouse or the primary gamepad is active
  • rebind helpers on InputMap<A>

§What it does not provide

  • camera, inventory, pad, menu, placement, or any other game logic
  • a built-in action enum
  • UI for controls menus
  • save/load for user settings
  • project-specific focus gating or business rules

This crate stays generic on purpose: the game defines actions, bindings, persistence, and meaning.

§Minimal demo

use bevy::input::gamepad::{GamepadAxis, GamepadButton};
use bevy::input::keyboard::KeyCode;
use bevy::prelude::*;
use cloudiful_bevy_input::{
    InputBinding, InputBindingsPlugin, InputButton, InputMap,
};

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Action {
    Jump,
    MoveX,
}

fn main() {
    let mut app = App::new();
    app.add_plugins(InputBindingsPlugin::<Action>::default())
        .add_systems(Startup, setup_bindings);

    app.update();

    let map = app.world().resource::<InputMap<Action>>();
    assert!(matches!(
        map.bindings(Action::Jump),
        [
            InputBinding::Button(InputButton::Key(KeyCode::Space)),
            InputBinding::Button(InputButton::Gamepad(GamepadButton::South)),
        ]
    ));
    assert!(matches!(
        map.bindings(Action::MoveX),
        [
            InputBinding::ButtonAxis {
                negative: InputButton::Key(KeyCode::KeyA),
                positive: InputButton::Key(KeyCode::KeyD),
            },
            InputBinding::GamepadAxis(GamepadAxis::LeftStickX),
        ]
    ));
}

fn setup_bindings(mut map: ResMut<InputMap<Action>>) {
    map.bind_key(Action::Jump, KeyCode::Space)
        .bind_gamepad_button(Action::Jump, GamepadButton::South)
        .bind_button_axis(
            Action::MoveX,
            InputButton::Key(KeyCode::KeyA),
            InputButton::Key(KeyCode::KeyD),
        )
        .bind_gamepad_axis(Action::MoveX, GamepadAxis::LeftStickX);
}

§Runtime Semantics

ActionState<A> stores four values per action:

  • pressed
  • just_pressed
  • just_released
  • value

pressed is threshold-based, not button-only. By default an action becomes pressed when value.abs() >= 0.5.

value is the strongest absolute contribution from the action’s bindings. If an action is bound to multiple inputs, the runtime keeps whichever binding has the largest absolute value for that frame.

InputSettings controls those thresholds:

  • action_press_threshold: defaults to 0.5
  • axis_activity_threshold: defaults to 0.2

The axis activity threshold only affects device-activity tracking. It does not clamp the stored action value.

§Rebinding

use bevy::input::keyboard::KeyCode;
use cloudiful_bevy_input::{InputButton, InputMap};

fn rebind_jump(map: &mut InputMap<Action>) {
    map.rebind_button(
        Action::Jump,
        InputButton::Key(KeyCode::Space),
        InputButton::Key(KeyCode::Enter),
    );
}

rebind_button(...) also updates ButtonAxis bindings when either side matches the old button. rebind_gamepad_axis(...) swaps a bound analog axis in place.

§Primary Gamepad Selection

PrimaryGamepad tracks which connected gamepad should drive gamepad bindings.

  • default mode is auto
  • auto mode selects the connected gamepad with the lowest entity index
  • PrimaryGamepad::select(entity) switches to manual mode
  • PrimaryGamepad::clear_manual() returns to auto mode
  • if the manually selected gamepad disappears, the selected gamepad becomes None

Manual selection example:

use bevy::prelude::Entity;
use cloudiful_bevy_input::PrimaryGamepad;

fn choose_primary(primary: &mut PrimaryGamepad, gamepad: Entity) {
    primary.select(gamepad);
}

fn reset_primary(primary: &mut PrimaryGamepad) {
    primary.clear_manual();
}

§Active Device Tracking

ActiveInputDevice records the last active source that crossed the configured activity threshold:

  • InputDevice::KeyboardMouse
  • InputDevice::Gamepad(Entity)

Keyboard/mouse activity wins first in frames where both keyboard and gamepad activity are detected. If no binding is active, the previous value is retained.

Structs§

ActionData
Per-action runtime state produced by InputBindingsPlugin.
ActionState
Per-action runtime state produced by InputBindingsPlugin.
ActiveInputDevice
Active-device and primary-gamepad tracking resources.
InputBindingsPlugin
Plugin that wires input resources and action-state updates.
InputMap
Generic input action traits, bindings, and mapping storage.
InputSettings
Per-action runtime state produced by InputBindingsPlugin.
PrimaryGamepad
Active-device and primary-gamepad tracking resources.

Enums§

InputBinding
Generic input action traits, bindings, and mapping storage.
InputButton
Generic input action traits, bindings, and mapping storage.
InputDevice
Active-device and primary-gamepad tracking resources.
PrimaryGamepadMode
Active-device and primary-gamepad tracking resources.

Traits§

InputAction
Generic input action traits, bindings, and mapping storage.