代码之家  ›  专栏  ›  技术社区  ›  sreysus

在Rust中表示游戏手柄状态结构的高效且符合人体工程学的方法

  •  0
  • sreysus  · 技术社区  · 9 月前

    我正在进行一个涉及游戏手柄输入的Rust项目,使用 gilrs 库(游戏输入库)。目前,我用以下结构表示控制器的状态:

    #[derive(Default, Clone)]
    pub struct GamepadState {
        axes: HashMap<gilrs::Axis, f32>,
        buttons: HashMap<gilrs::Button, bool>
    }
    

    这种设计允许我使用以下方法轻松检索轴和按钮的状态:

    impl GamepadState {
        pub fn axis(&self, axis: gilrs::Axis) -> f32 {
            self.axes.get(&axis).copied().unwrap_or(0_f32)
        }
        pub fn is_pressed(&self, button: gilrs::Button) -> bool {
            self.buttons.get(&button).copied().unwrap_or(false)
        }
    }
    

    这将允许在处理来自的事件时使用这样的代码 吉尔斯 :

    match event {
        gilrs::EventType::AxisChanged(c_axis, value, _) => {
            gamepad_state.axes.insert(c_axis, value);
        }
        gilrs::EventType::ButtonPressed(c_button, _) => {
            gamepad_state.buttons.insert(c_button, true);
        }
        gilrs::EventType::ButtonReleased(c_button, _) => {
            gamepad_state.buttons.insert(c_button, false);
        }
        _ => {}
    }
    

    我选择了 HashMap 使实现灵活简洁,但不是零成本抽象。我想优化这个设计,以获得更好的性能,同时保持清洁和符合人体工程学的API访问状态。

    如果我要替换 哈希图 ,它看起来像这样:

    match event {
        gilrs::EventType::AxisChanged(c_axis, value, _) => {
        use gilrs::Axis;        
            match c_axis {
                Axis::LeftStickX => joystick_state.left_x = value,
                Axis::LeftStickY => joystick_state.left_y = value,
                Axis::RightStickX => joystick_state.right_x = value,
                Axis::RightStickY => joystick_state.right_y = value,
            }
        },
        // similar handling for buttons, which is worse because triggers and d-pad actions are also considered buttons in `gilrs`
    }
    

    但这种方法感觉笨拙,可扩展性较差。

    我的问题:

    1. 我该如何重新设计这个 GamepadState 避免结构 哈希图 同时保持或提高性能?
    2. 在Rust中,有没有一种更好的方法来管理带有固定轴和按钮的游戏手柄状态,同时不牺牲人体工程学?

    非常感谢您就惯用、高效和可扩展的解决方案提供任何建议!

    1 回复  |  直到 9 月前
        1
  •  1
  •   Chayim Friedman    9 月前

    最快的方法是使用数组,您可以直接用枚举的值对其进行索引 Axis Button 然而,请注意,虽然这些枚举确实具有连续值,但不能保证它们具有连续值。幸运的是,如果有人将你的应用程序与不正确版本的库捆绑在一起,最糟糕的情况就是恐慌。

    const AXES_COUNT: usize = 9;
    const BUTTONS_COUNT: usize = 20;
    
    #[derive(Default, Clone)]
    pub struct GamepadState {
        axes: [f32; AXES_COUNT],
        buttons: [bool; BUTTONS_COUNT],
    }
    
    impl GamepadState {
        pub fn new() -> Self {
            Self {
                axes: [0.0; AXES_COUNT],
                buttons: [false; BUTTONS_COUNT],
            }
        }
    
        pub fn axis(&self, axis: gilrs::Axis) -> f32 {
            self.axes[axis as usize]
        }
    
        pub fn is_pressed(&self, button: gilrs::Button) -> bool {
            self.buttons[button as usize]
        }
    }
    

    如果你没有错过任何变体,这应该编译成最高性能的机器代码(这是一个数字和读/写的偏移量)。

    对于按钮,您可以考虑使用位图。如果您有许多实例,由于更好的缓存访问,这可能会更快 GamepadState (你可能不会)。

    推荐文章