robotengine.input

input 是 robotengine 中用于处理输入的模块。

在引擎初始化时,会根据 input_devices 参数创建 Input 实例,并将其传递给所有节点。

注意:在传递 input_devices 非空时,必须提前连接好相应的设备,否则程序会自动终止。

在节点的构造中,可以使用 _input(event: InputEvent) 来以回调的方式处理输入事件,也可以使用 self.input 来显式的访问 Input 实例。

  1"""
  2
  3input 是 robotengine 中用于处理输入的模块。
  4
  5在引擎初始化时,会根据 input_devices 参数创建 Input 实例,并将其传递给所有节点。
  6
  7注意:在传递 input_devices 非空时,必须提前连接好相应的设备,否则程序会自动终止。
  8
  9在节点的构造中,可以使用 _input(event: InputEvent) 来以回调的方式处理输入事件,也可以使用 self.input 来显式的访问 Input 实例。
 10
 11"""
 12
 13
 14from enum import Enum
 15import inputs
 16from robotengine.tools import error, warning, info
 17
 18# 定义 JoyButton 和 JoyAxis 枚举
 19class JoyButton(Enum):
 20    """ 手柄按钮枚举,以下以 Xbox 手柄为例 """
 21    JOY_BUTTON_INVALID = -1
 22    """ 无效按钮 """
 23    JOY_BUTTON_A = 0
 24    """ A 按钮 """
 25    JOY_BUTTON_B = 1
 26    """ B 按钮 """
 27    JOY_BUTTON_X = 2
 28    """ X 按钮 """
 29    JOY_BUTTON_Y = 3
 30    """ Y 按钮 """
 31    JOY_BUTTON_BACK = 4
 32    """ BACK 按钮 """
 33    JOY_BUTTON_START = 5
 34    """ START 按钮 """
 35    JOY_BUTTON_LEFT_STICK = 6
 36    """ 左摇杆按钮 """
 37    JOY_BUTTON_RIGHT_STICK = 7
 38    """ 右摇杆按钮 """
 39    JOY_BUTTON_LEFT_SHOULDER = 8
 40    """ 左扳机按钮 """
 41    JOY_BUTTON_RIGHT_SHOULDER = 9
 42    """ 右扳机按钮 """
 43
 44class JoyAxis(Enum):
 45    """ 手柄轴枚举,以下以 Xbox 手柄为例 """
 46    JOY_AXIS_INVALID = -1
 47    """ 无效轴 """
 48    JOY_AXIS_LEFT_X = 0
 49    """ 左摇杆 X 轴 """
 50    JOY_AXIS_LEFT_Y = 1
 51    """ 左摇杆 Y 轴 """
 52    JOY_AXIS_RIGHT_X = 2
 53    """ 右摇杆 X 轴 """
 54    JOY_AXIS_RIGHT_Y = 3
 55    """ 右摇杆 Y 轴 """
 56    JOY_AXIS_TRIGGER_LEFT = 4
 57    """ 左扳机轴 """
 58    JOY_AXIS_TRIGGER_RIGHT = 5
 59    """ 右扳机轴 """
 60    JOY_AXIS_DPAD_X = 6
 61    """ D-Pad X 轴 """
 62    JOY_AXIS_DPAD_Y = 7
 63    """ D-Pad Y 轴 """
 64
 65JOY_MAPPING = {
 66    "A": JoyButton.JOY_BUTTON_A,
 67    "B": JoyButton.JOY_BUTTON_B,
 68    "X": JoyButton.JOY_BUTTON_X,
 69    "Y": JoyButton.JOY_BUTTON_Y,
 70    "BACK": JoyButton.JOY_BUTTON_BACK,
 71    "START": JoyButton.JOY_BUTTON_START,
 72    "LEFT_STICK": JoyButton.JOY_BUTTON_LEFT_STICK,
 73    "RIGHT_STICK": JoyButton.JOY_BUTTON_RIGHT_STICK,
 74    "LEFT_SHOULDER": JoyButton.JOY_BUTTON_LEFT_SHOULDER,
 75    "RIGHT_SHOULDER": JoyButton.JOY_BUTTON_RIGHT_SHOULDER,
 76
 77    "LEFT_X": JoyAxis.JOY_AXIS_LEFT_X,
 78    "LEFT_Y": JoyAxis.JOY_AXIS_LEFT_Y,
 79    "RIGHT_X": JoyAxis.JOY_AXIS_RIGHT_X,
 80    "RIGHT_Y": JoyAxis.JOY_AXIS_RIGHT_Y,
 81    "TRIGGER_LEFT": JoyAxis.JOY_AXIS_TRIGGER_LEFT,
 82    "TRIGGER_RIGHT": JoyAxis.JOY_AXIS_TRIGGER_RIGHT,
 83    "DPAD_X": JoyAxis.JOY_AXIS_DPAD_X,
 84    "DPAD_Y": JoyAxis.JOY_AXIS_DPAD_Y
 85}
 86""" 
 87手柄按键映射
 88
 89这个表中的键值对表示了手柄按键和 JoyButton 与 JoyAxis 之间的映射关系。
 90
 91键值对的键表示手柄按键的名称,值表示手柄按键的枚举值。
 92
 93例如,"A" 键表示手柄的 A 按钮,其值为 JoyButton.JOY_BUTTON_A。
 94"""
 95
 96
 97INPUTS_BUTTON_MAPPING = {
 98    "BTN_SOUTH": JoyButton.JOY_BUTTON_A,
 99    "BTN_EAST": JoyButton.JOY_BUTTON_B,
100    "BTN_WEST": JoyButton.JOY_BUTTON_X,
101    "BTN_NORTH": JoyButton.JOY_BUTTON_Y,
102    "BTN_START": JoyButton.JOY_BUTTON_BACK,
103    "BTN_SELECT": JoyButton.JOY_BUTTON_START,
104    
105    "BTN_THUMBL": JoyButton.JOY_BUTTON_LEFT_STICK,
106    "BTN_THUMBR": JoyButton.JOY_BUTTON_RIGHT_STICK,
107    "BTN_TL": JoyButton.JOY_BUTTON_LEFT_SHOULDER,
108    "BTN_TR": JoyButton.JOY_BUTTON_RIGHT_SHOULDER,
109}
110
111INPUTS_AXIS_MAPPING = {
112    "ABS_X": JoyAxis.JOY_AXIS_LEFT_X,
113    "ABS_Y": JoyAxis.JOY_AXIS_LEFT_Y,
114    "ABS_RX": JoyAxis.JOY_AXIS_RIGHT_X,
115    "ABS_RY": JoyAxis.JOY_AXIS_RIGHT_Y,
116
117    "ABS_Z": JoyAxis.JOY_AXIS_TRIGGER_LEFT,
118    "ABS_RZ": JoyAxis.JOY_AXIS_TRIGGER_RIGHT,
119
120    "ABS_HAT0X": JoyAxis.JOY_AXIS_DPAD_X,
121    "ABS_HAT0Y": JoyAxis.JOY_AXIS_DPAD_Y
122}
123
124INPUTS_AXIS_VALUE_MAPPING = {
125    "ABS_X": 32767.0,
126    "ABS_Y": 32767.0,
127    "ABS_RX": 32767.0,
128    "ABS_RY": 32767.0,
129
130    "ABS_Z": 255.0,
131    "ABS_RZ": 255.0,
132
133    "ABS_HAT0X": 1.0,
134    "ABS_HAT0Y": 1.0
135}
136
137# 定义 InputEvent 类以及子类
138class InputEvent:
139    """ 输入事件基类 """
140    def __init__(self):
141        pass
142
143    def get_action_strength(self, action: str) -> float:
144        """ 返回某个动作的强度 """
145        pass
146
147    def is_action_pressed(self, action: str) -> bool:
148        """ 检查某个动作是否被按下 """
149        pass
150
151    def is_action_released(self, action: str) -> bool:
152        """ 检查某个动作是否被释放 """
153        pass
154
155class InputEventJoypadButton(InputEvent):
156    """手柄按钮事件"""
157    def __init__(self, button_index: JoyButton, pressed: bool):
158        """ 初始化手柄按键事件 """
159        self.button_index: JoyButton = button_index
160        """ 当前按键索引 """
161        self.pressed: bool = pressed
162        """ 当前按键是否被按下 """
163
164    def is_action_pressed(self, action: str) -> bool:
165        """ 检查当前事件是否是某个手柄按键被按下 """
166        if JOY_MAPPING.get(action) == self.button_index and self.pressed:
167            return True
168        return False
169
170    def is_action_released(self, action: str) -> bool:
171        """ 检查当前事件是否是某个手柄按键被释放 """
172        if JOY_MAPPING.get(action) == self.button_index and not self.pressed:
173            return True
174        return False
175    
176    def __repr__(self):
177        return f"JoypadButton({self.button_index}, {self.pressed})"
178
179class InputEventJoypadAxis(InputEvent):
180    """手柄轴事件"""
181    def __init__(self, axis: JoyAxis, axis_value: float):
182        """ 初始化手柄轴事件 """
183        self.axis: JoyAxis = axis
184        """ 当前轴索引 """
185        self.axis_value: float = axis_value
186        """ 当前轴值 """
187
188    def get_action_strength(self, action: str) -> float:
189        """ 检查当前事件的某个轴值 """
190        if JOY_MAPPING.get(action) == self.axis:
191            return self.axis_value
192        return 0.0
193    
194    def __repr__(self):
195        return f"JoypadAxis({self.axis}, {self.axis_value})"
196
197class GamepadListener():
198    def __init__(self):
199        self.devices = inputs.devices.gamepads
200        if not self.devices:
201            error("您开启了 Gamepad 输入检测,但是未检测到 Gamepad 设备,请连接 Gamepad 设备后重试")
202        else:
203            info(f"您开启了 Gamepad 输入检测,检测到 {len(self.devices)} 个 Gamepad 设备, 将使用第一个设备 {self.devices[0].name} 进行输入检测")
204
205    def listen(self) -> InputEvent: # type: ignore
206        """监听手柄输入并生成事件"""
207        _events = inputs.get_gamepad()
208        for _event in _events:
209            if _event.ev_type == 'Key':
210                # 假设是按键事件
211                button_index = JoyButton(INPUTS_BUTTON_MAPPING.get(_event.code))  # 获取按键代码
212                pressed = _event.state == 1
213                input_event = InputEventJoypadButton(button_index, pressed)
214                yield input_event
215            elif _event.ev_type == 'Absolute':
216                # 假设是轴向事件
217                axis = JoyAxis(INPUTS_AXIS_MAPPING.get(_event.code))  # 获取轴向代码
218                axis_value = _event.state / INPUTS_AXIS_VALUE_MAPPING.get(_event.code)
219                input_event = InputEventJoypadAxis(axis, axis_value)
220                yield input_event
221
222class Input:
223    """
224    输入类,每个 Node 节点都可以使用 self.input 来获取 Input 对象。
225
226    输入类的使用方法:
227
228        # 获取输入对象
229        input = self.input
230
231        # 检查某个动作是否被按下
232        if input.is_action_pressed("A"):
233            print("A 键被按下")
234
235        # 检查某个动作的强度
236        print(input.get_action_strength("LEFT_X"))
237
238    Input 与 _input 的用法有所不同
239
240    Input 在检测按键是否按下时,如果此时函数连续被调用,则会连续返回 True,直到按键被释放。
241
242    而 _input 则类似于中断,当按键被按下后,只会在 _input 事件中检测到一次。
243
244    """
245    def __init__(self):
246        self._button_states = {
247            'A': False,
248            'B': False,
249            'X': False,
250            'Y': False,
251            'BACK': False,
252            'START': False,
253            'LEFT_STICK': False,
254            'RIGHT_STICK': False,
255            'LEFT_SHOULDER': False,
256            'RIGHT_SHOULDER': False,
257        }
258
259        self._axis_states = {
260            'LEFT_X': 0.0,
261            'LEFT_Y': 0.0,
262            'RIGHT_X': 0.0,
263            'RIGHT_Y': 0.0,
264            'TRIGGER_LEFT': 0.0,
265            'TRIGGER_RIGHT': 0.0,
266            'DPAD_X': 0.0,
267            'DPAD_Y': 0.0
268        }
269
270    def _get_key_from_value(self, mapping, value):
271        for key, val in mapping.items():
272            if val == value:
273                return key
274        return None
275
276    def _update(self, event: InputEvent):
277        if isinstance(event, InputEventJoypadButton):
278            self._button_states[self._get_key_from_value(JOY_MAPPING, event.button_index)] = event.pressed
279        elif isinstance(event, InputEventJoypadAxis):
280            self._axis_states[self._get_key_from_value(JOY_MAPPING, event.axis)] = event.axis_value
281
282    def get_axis(self, negative_action: str, positive_action: str) -> float:
283        if negative_action not in self.axis_states or positive_action not in self.axis_states:
284            raise ValueError(f"无效的 axis 动作: {negative_action}, {positive_action}")
285        negative = self._axis_states[negative_action]
286        positive = self._axis_states[positive_action]
287
288        return positive - negative
289    
290    def get_action_strength(self, action: str) -> float:
291        if action in self._axis_states:
292            return self._axis_states[action]
293        else:
294            return 0.0
295    
296    def is_action_pressed(self, action: str) -> bool:
297        if action in self._button_states:
298            return self._button_states[action]
299        else:
300            return False
301        
302    def is_action_released(self, action: str) -> bool:
303        if action in self._button_states:
304            return not self._button_states[action]
305        else:
306            return False
307        
308    def flush_action(self, action: str) -> None:
309        if action in self._button_states:
310            self._button_states[action] = False
311        elif action in self._axis_states:
312            self._axis_states[action] = 0.0
313    
314    def is_anything_pressed(self) -> bool:
315        for value in self._button_states.values():
316            if value:
317                return True
318        return False
class JoyButton(enum.Enum):
20class JoyButton(Enum):
21    """ 手柄按钮枚举,以下以 Xbox 手柄为例 """
22    JOY_BUTTON_INVALID = -1
23    """ 无效按钮 """
24    JOY_BUTTON_A = 0
25    """ A 按钮 """
26    JOY_BUTTON_B = 1
27    """ B 按钮 """
28    JOY_BUTTON_X = 2
29    """ X 按钮 """
30    JOY_BUTTON_Y = 3
31    """ Y 按钮 """
32    JOY_BUTTON_BACK = 4
33    """ BACK 按钮 """
34    JOY_BUTTON_START = 5
35    """ START 按钮 """
36    JOY_BUTTON_LEFT_STICK = 6
37    """ 左摇杆按钮 """
38    JOY_BUTTON_RIGHT_STICK = 7
39    """ 右摇杆按钮 """
40    JOY_BUTTON_LEFT_SHOULDER = 8
41    """ 左扳机按钮 """
42    JOY_BUTTON_RIGHT_SHOULDER = 9
43    """ 右扳机按钮 """

手柄按钮枚举,以下以 Xbox 手柄为例

JOY_BUTTON_INVALID = <JoyButton.JOY_BUTTON_INVALID: -1>

无效按钮

JOY_BUTTON_A = <JoyButton.JOY_BUTTON_A: 0>

A 按钮

JOY_BUTTON_B = <JoyButton.JOY_BUTTON_B: 1>

B 按钮

JOY_BUTTON_X = <JoyButton.JOY_BUTTON_X: 2>

X 按钮

JOY_BUTTON_Y = <JoyButton.JOY_BUTTON_Y: 3>

Y 按钮

JOY_BUTTON_BACK = <JoyButton.JOY_BUTTON_BACK: 4>

BACK 按钮

JOY_BUTTON_START = <JoyButton.JOY_BUTTON_START: 5>

START 按钮

JOY_BUTTON_LEFT_STICK = <JoyButton.JOY_BUTTON_LEFT_STICK: 6>

左摇杆按钮

JOY_BUTTON_RIGHT_STICK = <JoyButton.JOY_BUTTON_RIGHT_STICK: 7>

右摇杆按钮

JOY_BUTTON_LEFT_SHOULDER = <JoyButton.JOY_BUTTON_LEFT_SHOULDER: 8>

左扳机按钮

JOY_BUTTON_RIGHT_SHOULDER = <JoyButton.JOY_BUTTON_RIGHT_SHOULDER: 9>

右扳机按钮

Inherited Members
enum.Enum
name
value
class JoyAxis(enum.Enum):
45class JoyAxis(Enum):
46    """ 手柄轴枚举,以下以 Xbox 手柄为例 """
47    JOY_AXIS_INVALID = -1
48    """ 无效轴 """
49    JOY_AXIS_LEFT_X = 0
50    """ 左摇杆 X 轴 """
51    JOY_AXIS_LEFT_Y = 1
52    """ 左摇杆 Y 轴 """
53    JOY_AXIS_RIGHT_X = 2
54    """ 右摇杆 X 轴 """
55    JOY_AXIS_RIGHT_Y = 3
56    """ 右摇杆 Y 轴 """
57    JOY_AXIS_TRIGGER_LEFT = 4
58    """ 左扳机轴 """
59    JOY_AXIS_TRIGGER_RIGHT = 5
60    """ 右扳机轴 """
61    JOY_AXIS_DPAD_X = 6
62    """ D-Pad X 轴 """
63    JOY_AXIS_DPAD_Y = 7
64    """ D-Pad Y 轴 """

手柄轴枚举,以下以 Xbox 手柄为例

JOY_AXIS_INVALID = <JoyAxis.JOY_AXIS_INVALID: -1>

无效轴

JOY_AXIS_LEFT_X = <JoyAxis.JOY_AXIS_LEFT_X: 0>

左摇杆 X 轴

JOY_AXIS_LEFT_Y = <JoyAxis.JOY_AXIS_LEFT_Y: 1>

左摇杆 Y 轴

JOY_AXIS_RIGHT_X = <JoyAxis.JOY_AXIS_RIGHT_X: 2>

右摇杆 X 轴

JOY_AXIS_RIGHT_Y = <JoyAxis.JOY_AXIS_RIGHT_Y: 3>

右摇杆 Y 轴

JOY_AXIS_TRIGGER_LEFT = <JoyAxis.JOY_AXIS_TRIGGER_LEFT: 4>

左扳机轴

JOY_AXIS_TRIGGER_RIGHT = <JoyAxis.JOY_AXIS_TRIGGER_RIGHT: 5>

右扳机轴

JOY_AXIS_DPAD_X = <JoyAxis.JOY_AXIS_DPAD_X: 6>

D-Pad X 轴

JOY_AXIS_DPAD_Y = <JoyAxis.JOY_AXIS_DPAD_Y: 7>

D-Pad Y 轴

Inherited Members
enum.Enum
name
value
JOY_MAPPING = {'A': <JoyButton.JOY_BUTTON_A: 0>, 'B': <JoyButton.JOY_BUTTON_B: 1>, 'X': <JoyButton.JOY_BUTTON_X: 2>, 'Y': <JoyButton.JOY_BUTTON_Y: 3>, 'BACK': <JoyButton.JOY_BUTTON_BACK: 4>, 'START': <JoyButton.JOY_BUTTON_START: 5>, 'LEFT_STICK': <JoyButton.JOY_BUTTON_LEFT_STICK: 6>, 'RIGHT_STICK': <JoyButton.JOY_BUTTON_RIGHT_STICK: 7>, 'LEFT_SHOULDER': <JoyButton.JOY_BUTTON_LEFT_SHOULDER: 8>, 'RIGHT_SHOULDER': <JoyButton.JOY_BUTTON_RIGHT_SHOULDER: 9>, 'LEFT_X': <JoyAxis.JOY_AXIS_LEFT_X: 0>, 'LEFT_Y': <JoyAxis.JOY_AXIS_LEFT_Y: 1>, 'RIGHT_X': <JoyAxis.JOY_AXIS_RIGHT_X: 2>, 'RIGHT_Y': <JoyAxis.JOY_AXIS_RIGHT_Y: 3>, 'TRIGGER_LEFT': <JoyAxis.JOY_AXIS_TRIGGER_LEFT: 4>, 'TRIGGER_RIGHT': <JoyAxis.JOY_AXIS_TRIGGER_RIGHT: 5>, 'DPAD_X': <JoyAxis.JOY_AXIS_DPAD_X: 6>, 'DPAD_Y': <JoyAxis.JOY_AXIS_DPAD_Y: 7>}

手柄按键映射

这个表中的键值对表示了手柄按键和 JoyButton 与 JoyAxis 之间的映射关系。

键值对的键表示手柄按键的名称,值表示手柄按键的枚举值。

例如,"A" 键表示手柄的 A 按钮,其值为 JoyButton.JOY_BUTTON_A

INPUTS_BUTTON_MAPPING = {'BTN_SOUTH': <JoyButton.JOY_BUTTON_A: 0>, 'BTN_EAST': <JoyButton.JOY_BUTTON_B: 1>, 'BTN_WEST': <JoyButton.JOY_BUTTON_X: 2>, 'BTN_NORTH': <JoyButton.JOY_BUTTON_Y: 3>, 'BTN_START': <JoyButton.JOY_BUTTON_BACK: 4>, 'BTN_SELECT': <JoyButton.JOY_BUTTON_START: 5>, 'BTN_THUMBL': <JoyButton.JOY_BUTTON_LEFT_STICK: 6>, 'BTN_THUMBR': <JoyButton.JOY_BUTTON_RIGHT_STICK: 7>, 'BTN_TL': <JoyButton.JOY_BUTTON_LEFT_SHOULDER: 8>, 'BTN_TR': <JoyButton.JOY_BUTTON_RIGHT_SHOULDER: 9>}
INPUTS_AXIS_MAPPING = {'ABS_X': <JoyAxis.JOY_AXIS_LEFT_X: 0>, 'ABS_Y': <JoyAxis.JOY_AXIS_LEFT_Y: 1>, 'ABS_RX': <JoyAxis.JOY_AXIS_RIGHT_X: 2>, 'ABS_RY': <JoyAxis.JOY_AXIS_RIGHT_Y: 3>, 'ABS_Z': <JoyAxis.JOY_AXIS_TRIGGER_LEFT: 4>, 'ABS_RZ': <JoyAxis.JOY_AXIS_TRIGGER_RIGHT: 5>, 'ABS_HAT0X': <JoyAxis.JOY_AXIS_DPAD_X: 6>, 'ABS_HAT0Y': <JoyAxis.JOY_AXIS_DPAD_Y: 7>}
INPUTS_AXIS_VALUE_MAPPING = {'ABS_X': 32767.0, 'ABS_Y': 32767.0, 'ABS_RX': 32767.0, 'ABS_RY': 32767.0, 'ABS_Z': 255.0, 'ABS_RZ': 255.0, 'ABS_HAT0X': 1.0, 'ABS_HAT0Y': 1.0}
class InputEvent:
139class InputEvent:
140    """ 输入事件基类 """
141    def __init__(self):
142        pass
143
144    def get_action_strength(self, action: str) -> float:
145        """ 返回某个动作的强度 """
146        pass
147
148    def is_action_pressed(self, action: str) -> bool:
149        """ 检查某个动作是否被按下 """
150        pass
151
152    def is_action_released(self, action: str) -> bool:
153        """ 检查某个动作是否被释放 """
154        pass

输入事件基类

def get_action_strength(self, action: str) -> float:
144    def get_action_strength(self, action: str) -> float:
145        """ 返回某个动作的强度 """
146        pass

返回某个动作的强度

def is_action_pressed(self, action: str) -> bool:
148    def is_action_pressed(self, action: str) -> bool:
149        """ 检查某个动作是否被按下 """
150        pass

检查某个动作是否被按下

def is_action_released(self, action: str) -> bool:
152    def is_action_released(self, action: str) -> bool:
153        """ 检查某个动作是否被释放 """
154        pass

检查某个动作是否被释放

class InputEventJoypadButton(InputEvent):
156class InputEventJoypadButton(InputEvent):
157    """手柄按钮事件"""
158    def __init__(self, button_index: JoyButton, pressed: bool):
159        """ 初始化手柄按键事件 """
160        self.button_index: JoyButton = button_index
161        """ 当前按键索引 """
162        self.pressed: bool = pressed
163        """ 当前按键是否被按下 """
164
165    def is_action_pressed(self, action: str) -> bool:
166        """ 检查当前事件是否是某个手柄按键被按下 """
167        if JOY_MAPPING.get(action) == self.button_index and self.pressed:
168            return True
169        return False
170
171    def is_action_released(self, action: str) -> bool:
172        """ 检查当前事件是否是某个手柄按键被释放 """
173        if JOY_MAPPING.get(action) == self.button_index and not self.pressed:
174            return True
175        return False
176    
177    def __repr__(self):
178        return f"JoypadButton({self.button_index}, {self.pressed})"

手柄按钮事件

InputEventJoypadButton(button_index: JoyButton, pressed: bool)
158    def __init__(self, button_index: JoyButton, pressed: bool):
159        """ 初始化手柄按键事件 """
160        self.button_index: JoyButton = button_index
161        """ 当前按键索引 """
162        self.pressed: bool = pressed
163        """ 当前按键是否被按下 """

初始化手柄按键事件

button_index: JoyButton

当前按键索引

pressed: bool

当前按键是否被按下

def is_action_pressed(self, action: str) -> bool:
165    def is_action_pressed(self, action: str) -> bool:
166        """ 检查当前事件是否是某个手柄按键被按下 """
167        if JOY_MAPPING.get(action) == self.button_index and self.pressed:
168            return True
169        return False

检查当前事件是否是某个手柄按键被按下

def is_action_released(self, action: str) -> bool:
171    def is_action_released(self, action: str) -> bool:
172        """ 检查当前事件是否是某个手柄按键被释放 """
173        if JOY_MAPPING.get(action) == self.button_index and not self.pressed:
174            return True
175        return False

检查当前事件是否是某个手柄按键被释放

Inherited Members
InputEvent
get_action_strength
class InputEventJoypadAxis(InputEvent):
180class InputEventJoypadAxis(InputEvent):
181    """手柄轴事件"""
182    def __init__(self, axis: JoyAxis, axis_value: float):
183        """ 初始化手柄轴事件 """
184        self.axis: JoyAxis = axis
185        """ 当前轴索引 """
186        self.axis_value: float = axis_value
187        """ 当前轴值 """
188
189    def get_action_strength(self, action: str) -> float:
190        """ 检查当前事件的某个轴值 """
191        if JOY_MAPPING.get(action) == self.axis:
192            return self.axis_value
193        return 0.0
194    
195    def __repr__(self):
196        return f"JoypadAxis({self.axis}, {self.axis_value})"

手柄轴事件

InputEventJoypadAxis(axis: JoyAxis, axis_value: float)
182    def __init__(self, axis: JoyAxis, axis_value: float):
183        """ 初始化手柄轴事件 """
184        self.axis: JoyAxis = axis
185        """ 当前轴索引 """
186        self.axis_value: float = axis_value
187        """ 当前轴值 """

初始化手柄轴事件

axis: JoyAxis

当前轴索引

axis_value: float

当前轴值

def get_action_strength(self, action: str) -> float:
189    def get_action_strength(self, action: str) -> float:
190        """ 检查当前事件的某个轴值 """
191        if JOY_MAPPING.get(action) == self.axis:
192            return self.axis_value
193        return 0.0

检查当前事件的某个轴值

class GamepadListener:
198class GamepadListener():
199    def __init__(self):
200        self.devices = inputs.devices.gamepads
201        if not self.devices:
202            error("您开启了 Gamepad 输入检测,但是未检测到 Gamepad 设备,请连接 Gamepad 设备后重试")
203        else:
204            info(f"您开启了 Gamepad 输入检测,检测到 {len(self.devices)} 个 Gamepad 设备, 将使用第一个设备 {self.devices[0].name} 进行输入检测")
205
206    def listen(self) -> InputEvent: # type: ignore
207        """监听手柄输入并生成事件"""
208        _events = inputs.get_gamepad()
209        for _event in _events:
210            if _event.ev_type == 'Key':
211                # 假设是按键事件
212                button_index = JoyButton(INPUTS_BUTTON_MAPPING.get(_event.code))  # 获取按键代码
213                pressed = _event.state == 1
214                input_event = InputEventJoypadButton(button_index, pressed)
215                yield input_event
216            elif _event.ev_type == 'Absolute':
217                # 假设是轴向事件
218                axis = JoyAxis(INPUTS_AXIS_MAPPING.get(_event.code))  # 获取轴向代码
219                axis_value = _event.state / INPUTS_AXIS_VALUE_MAPPING.get(_event.code)
220                input_event = InputEventJoypadAxis(axis, axis_value)
221                yield input_event
devices
def listen(self) -> InputEvent:
206    def listen(self) -> InputEvent: # type: ignore
207        """监听手柄输入并生成事件"""
208        _events = inputs.get_gamepad()
209        for _event in _events:
210            if _event.ev_type == 'Key':
211                # 假设是按键事件
212                button_index = JoyButton(INPUTS_BUTTON_MAPPING.get(_event.code))  # 获取按键代码
213                pressed = _event.state == 1
214                input_event = InputEventJoypadButton(button_index, pressed)
215                yield input_event
216            elif _event.ev_type == 'Absolute':
217                # 假设是轴向事件
218                axis = JoyAxis(INPUTS_AXIS_MAPPING.get(_event.code))  # 获取轴向代码
219                axis_value = _event.state / INPUTS_AXIS_VALUE_MAPPING.get(_event.code)
220                input_event = InputEventJoypadAxis(axis, axis_value)
221                yield input_event

监听手柄输入并生成事件

class Input:
223class Input:
224    """
225    输入类,每个 Node 节点都可以使用 self.input 来获取 Input 对象。
226
227    输入类的使用方法:
228
229        # 获取输入对象
230        input = self.input
231
232        # 检查某个动作是否被按下
233        if input.is_action_pressed("A"):
234            print("A 键被按下")
235
236        # 检查某个动作的强度
237        print(input.get_action_strength("LEFT_X"))
238
239    Input 与 _input 的用法有所不同
240
241    Input 在检测按键是否按下时,如果此时函数连续被调用,则会连续返回 True,直到按键被释放。
242
243    而 _input 则类似于中断,当按键被按下后,只会在 _input 事件中检测到一次。
244
245    """
246    def __init__(self):
247        self._button_states = {
248            'A': False,
249            'B': False,
250            'X': False,
251            'Y': False,
252            'BACK': False,
253            'START': False,
254            'LEFT_STICK': False,
255            'RIGHT_STICK': False,
256            'LEFT_SHOULDER': False,
257            'RIGHT_SHOULDER': False,
258        }
259
260        self._axis_states = {
261            'LEFT_X': 0.0,
262            'LEFT_Y': 0.0,
263            'RIGHT_X': 0.0,
264            'RIGHT_Y': 0.0,
265            'TRIGGER_LEFT': 0.0,
266            'TRIGGER_RIGHT': 0.0,
267            'DPAD_X': 0.0,
268            'DPAD_Y': 0.0
269        }
270
271    def _get_key_from_value(self, mapping, value):
272        for key, val in mapping.items():
273            if val == value:
274                return key
275        return None
276
277    def _update(self, event: InputEvent):
278        if isinstance(event, InputEventJoypadButton):
279            self._button_states[self._get_key_from_value(JOY_MAPPING, event.button_index)] = event.pressed
280        elif isinstance(event, InputEventJoypadAxis):
281            self._axis_states[self._get_key_from_value(JOY_MAPPING, event.axis)] = event.axis_value
282
283    def get_axis(self, negative_action: str, positive_action: str) -> float:
284        if negative_action not in self.axis_states or positive_action not in self.axis_states:
285            raise ValueError(f"无效的 axis 动作: {negative_action}, {positive_action}")
286        negative = self._axis_states[negative_action]
287        positive = self._axis_states[positive_action]
288
289        return positive - negative
290    
291    def get_action_strength(self, action: str) -> float:
292        if action in self._axis_states:
293            return self._axis_states[action]
294        else:
295            return 0.0
296    
297    def is_action_pressed(self, action: str) -> bool:
298        if action in self._button_states:
299            return self._button_states[action]
300        else:
301            return False
302        
303    def is_action_released(self, action: str) -> bool:
304        if action in self._button_states:
305            return not self._button_states[action]
306        else:
307            return False
308        
309    def flush_action(self, action: str) -> None:
310        if action in self._button_states:
311            self._button_states[action] = False
312        elif action in self._axis_states:
313            self._axis_states[action] = 0.0
314    
315    def is_anything_pressed(self) -> bool:
316        for value in self._button_states.values():
317            if value:
318                return True
319        return False

输入类,每个 Node 节点都可以使用 self.input 来获取 Input 对象。

输入类的使用方法:

# 获取输入对象
input = self.input

# 检查某个动作是否被按下
if input.is_action_pressed("A"):
    print("A 键被按下")

# 检查某个动作的强度
print(input.get_action_strength("LEFT_X"))

Input 与 _input 的用法有所不同

Input 在检测按键是否按下时,如果此时函数连续被调用,则会连续返回 True,直到按键被释放。

而 _input 则类似于中断,当按键被按下后,只会在 _input 事件中检测到一次。

def get_axis(self, negative_action: str, positive_action: str) -> float:
283    def get_axis(self, negative_action: str, positive_action: str) -> float:
284        if negative_action not in self.axis_states or positive_action not in self.axis_states:
285            raise ValueError(f"无效的 axis 动作: {negative_action}, {positive_action}")
286        negative = self._axis_states[negative_action]
287        positive = self._axis_states[positive_action]
288
289        return positive - negative
def get_action_strength(self, action: str) -> float:
291    def get_action_strength(self, action: str) -> float:
292        if action in self._axis_states:
293            return self._axis_states[action]
294        else:
295            return 0.0
def is_action_pressed(self, action: str) -> bool:
297    def is_action_pressed(self, action: str) -> bool:
298        if action in self._button_states:
299            return self._button_states[action]
300        else:
301            return False
def is_action_released(self, action: str) -> bool:
303    def is_action_released(self, action: str) -> bool:
304        if action in self._button_states:
305            return not self._button_states[action]
306        else:
307            return False
def flush_action(self, action: str) -> None:
309    def flush_action(self, action: str) -> None:
310        if action in self._button_states:
311            self._button_states[action] = False
312        elif action in self._axis_states:
313            self._axis_states[action] = 0.0
def is_anything_pressed(self) -> bool:
315    def is_anything_pressed(self) -> bool:
316        for value in self._button_states.values():
317            if value:
318                return True
319        return False