#action #input #bevy #mapping #game-engine #gamedev

action_maps

Bevy的动态操作映射系统

5个不稳定版本

0.3.1 2023年12月26日
0.3.0 2023年12月24日
0.2.1 2023年12月24日
0.2.0 2023年12月24日
0.1.0 2023年11月23日

979游戏开发

MIT 许可证

52KB
1K SLoC

操作映射

Bevy的动态操作映射系统。

为什么要使用操作映射?

操作映射提供了一个类似于Unity的InputSystem和Godot的Input Map的接口。使用操作映射,您可以将功能分配给任何可用的Bevy输入项,而无需直接与输入本身交互。

目前,这仅适用于按钮类型输入。

定义操作

在内部,操作仅使用一个字符串来跟踪其身份。定义操作就像将操作名称和输入插入到控制方案中一样简单。

fn bind_keys(
    mut control_scheme: ResMut<ControlScheme>
) {
    control_scheme.insert("Jump", KeyCode::Space);
    control_scheme.insert("A", KeyCode::A);
    // or...
    control_scheme.set(make_controls!(
        ("Jump", KeyCode::Space),
        ("A", KeyCode::A),
    ));
}

处理输入

操作映射是现有Bevy Input<T> 的包装器,因此使用它们的接口完全相同。

use action_maps::prelude::*;

fn handle_input(
    actions: Res<ActionInput>
) {
    if action.just_pressed("Jump") {
        println!("Your character jumps!");
    }
}

不同的方式

操作映射方法接受任何实现了 Into<Action> 的项目。

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Actions {
    Up,
    Left,
    Down,
    Right
}

impl Into<Action> for Actions {
    fn into(self) -> Action {
        match self {
            Actions::Up => Action::from("Up"),
            Actions::Left => Action::from("Left"),
            Actions::Down => Action::from("Down"),
            Actions::Right => Action::from("Right"),
            Actions::ChangeColor => Action::from("ChangeColor"),
        }
    }
}

fn bind_keys(
    mut control_scheme: ResMut<ControlScheme>
) {
    control_scheme.insert(Actions::Up, KeyCode::W);
    // or...
    control_scheme.set(make_controls!(
        (Actions::Up, KeyCode::W),
    ));
}

通用输入

操作映射提供了另一层来帮助您定义按键绑定:UniversalInput。UniversalInput是Bevy中可用的每个按钮类型输入设备的简单包装器。操作映射方法可以接受任何这些输入类型并像使用它们一样使用它们。

fn bind_keys(
    mut control_scheme: ResMut<ControlScheme>
) {
    control_scheme.insert("Up", KeyCode::W);
    control_scheme.insert("Down", ScanCode(get_scan_code("W")));
    control_scheme.insert("Shoot", MouseButton::Left);
}

使用扫描码

操作映射提供了一个辅助函数 action_maps::get_scan_code 来帮助在Bevy中使用扫描码。此函数非常基础,可能容易遗漏按键(更不用说完全缺乏对Linux的支持)。希望随着 这个 PR和Bevy 0.13,它将变得不再需要。

let qwerty_w_scancode = action_maps::get_scan_code("W");

多人游戏

使用辅助类型 MultiInputMultiScheme,多人游戏变得简单。您可以从 action_maps::multiplayer 简单地导入您所需的一切。要开始,请添加 MultiActionMapPlugin。

fn bind_keys(
    mut inputs: ResMut<MultiInput>,
    mut control_schemes: ResMut<MultiScheme>,
) {
    make_multi_input!(
        inputs,
        control_schemes,
        (
            (Actions::Up, ScanCode(get_scan_code("W"))),
            (Actions::Left, ScanCode(get_scan_code("A"))),
            (Actions::Down, ScanCode(get_scan_code("S"))),
            (Actions::Right, ScanCode(get_scan_code("D"))),
        ),
        (
            (Actions::Up, ScanCode(get_scan_code("Up"))),
            (Actions::Left, ScanCode(get_scan_code("Left"))),
            (Actions::Down, ScanCode(get_scan_code("Down"))),
            (Actions::Right, ScanCode(get_scan_code("Right"))),
        )
    );
}


fn handle_input(
    multi_input: Res<MultiInput>,
    mut query: Query<(&mut Transform, &PlayerId)>,
) {
    for (mut transform, PlayerId(id)) in query.iter_mut() {
        let actions: &ActionInput = multi_input.get(*id).unwrap();
        // handle controls here the same way you would for singleplayer!
    }
}

计划中的更改

  • 支持轴类型输入

潜在问题

  • 操作映射使用事件系统来读取输入。因此,如果您没有正确确保系统的顺序,您可能会在输入注册和系统能够处理输入更新之间出现一帧的延迟。

依赖关系

~21MB
~392K SLoC