控制器和操纵杆输入

这个 input 模块允许您接受来自USB或蓝牙人机接口设备(HID)的输入。提供了用于使用游戏控制器、操纵杆和Apple遥控器的高级类,具有命名和标准化的输入。还为抽出平板电脑提供了基本支持,如Wacom制造的平板电脑。

游戏控制器抽象最适合现代双模拟手柄控制器,例如来自视频游戏机的控制器。操纵杆的抽象更加通用,适合具有任意数量的按钮、绝对或相对轴和帽子的设备。这包括飞行操纵杆、方向盘等设备,以及几乎任何其他具有数字和/或模拟输入的设备。对于大多数类型的游戏,建议使用游戏控制器抽象化。

对于高级用例,还可以直接访问低级输入设备。如果您需要直接访问原始输入,而不需要标准化,这会很有用。对于大多数应用程序和游戏,这不是必需的。

这个 input 模块提供了几种查询设备的方法,以及支持控制器热插拔的ControllerManager类:

# get a list of all low-level input devices:
devices = pyglet.input.get_devices()

# get a list of all controllers:
controllers = pyglet.input.get_controllers()

# get a list of all joysticks:
joysticks = pyglet.input.get_joysticks()

# get a list of tablets:
tablets = pyglet.input.get_tablets()

# get an Apple Remote, if available:
remote = pyglet.input.get_apple_remote()

# create a ControllerManager instance:
controller_manager = pyglet.input.ControllerManager()

使用控制器

控制器有一组严格定义的输入,模仿现代双模拟棒状视频游戏控制台控制器的布局。这包括两个模拟操纵杆、模拟触发器、方向垫(DPAD)、面部和肩部按钮以及开始/后退/引导和操纵杆按钮。许多控制器还包括播放隆隆效果(振动)的能力。以下平台接口用于控制器支持:

站台

接口

Linux

Evdev

窗口

DirectInput和XInput

在DirectInput上未实现Rumble

MacOSX

IOKit

隆隆尚未实施

在使用控制器之前,您必须找到并打开它。您可以手动列出并打开控制器,也可以使用 ControllerManager 。ControllerManager为轻松处理控制器的热插拔提供了有用的事件,这将在下一节中介绍。不过,首先让我们看看如何手动完成此操作。要获取当前连接到您的计算机的所有控制器的列表,请调用pyglet.input.Get_Controlors()::

controllers = pyglet.input.get_controllers()

然后从列表中选择一个控制器并调用 Controller.open() 要打开它,请执行以下操作:

if controllers:
    controller = controllers[0]
    controller.open()

一旦打开,您就可以开始接收来自输入的数据。各种模拟和数字 Control 定义了类型,这些类型会自动标准化为一致的范围。以下模拟控件可用:

名字

类型

量程

Leftx

浮动

-1~1

左撇子

浮动

-1~1

右x

浮动

-1~1

右转

浮动

-1~1

左触发器

浮动

0~1

右触发器

浮动

0~1

有以下数字控制可用:

名字

一个

“南”字按钮

B类

“东面”按钮

X

“西面”按钮

“北”字按钮

左肩

右肩

开始

在某些控制器上称为“选项”

在某些控制器上称为“选择”或“共享”

指南

通常在中心,带有公司标志

左撇子

按下左侧的模拟杆

右手棒

按下右侧的模拟杆

Dpleft

阳光明媚

小狗

DpDown

可以通过两种方式读取这些值。首先,您可以在游戏循环中手动查询它们。上面列出的所有控件名称都是控制器实例上的属性::

# controller_instance.a       (boolean)
# controller_instance.leftx   (float)

if controller_instance.a == True:
    # do something

或者,由于控制器是 EventDispatcher ,则在任意值发生更改时将调度事件。这通常是处理输入的推荐方式,因为它减少了由于轮询速度慢而导致“错过”按钮按下的机会。不同的控件分为以下事件类型:

事件

立论

类型

on_button_press

控制器,按钮名称

Controller, str

on_button_release

控制器,按钮名称

Controller, str

on_stick_motion

控制器、杆名称、x值、y值

Controller, str, float, float

on_dpad_motion

控制器,左、右、上、下

Controller, bool, bool, bool, bool

on_trigger_motion

控制器、触发器名称、值

Controller, str, float

可按如下方式处理模拟事件::

@controller.event
def on_stick_motion(controller, name, x_value, y_value):

    if name == "leftstick":
        # Do something with the x/y_values
    elif name == "rightstick":
        # Do something with the x/y_values

@controller.event
def on_trigger_motion(controller, name, value):

    if name == "lefttrigger":
        # Do something with the value
    elif name == "righttrigger":
        # Do something with the value

数字事件可按如下方式处理:

@controller.event
def on_button_press(controller, button_name):
    if button_name == 'a':
        # start firing
    elif button_name == 'b':
        # do something else


@controller.event
def on_button_release(controller, button_name):
    if button_name == 'a':
        # stop firing
    elif button_name == 'b':
        # do something else

最后,可以按如下方式处理方向板事件::

@controller.event
def on_dpad_motion(controller, dpleft, dpright, dpup, dpdown):
    if dpup:
        # move up
    if dpdown:
        # move down
    if dpleft:
        # move left
    if dpright:
        # move right

隆隆声

许多控制器还支持播放隆隆(振动)效果。有强有弱,可以独立发挥::

controller.rumble_play_weak(strength, duration=0.5)
controller.rumble_play_strong(strength, duration=0.5)

这个 strength 参数应在0-1的范围内。超出此范围的值将被钳制。可选的 duration 参数以秒为单位。最长持续时间因平台而异,但通常至少为5秒。如果在现有效果仍在播放时播放另一种效果,它将替换该效果。您还可以随时停止播放隆隆效果::

controller.rumble_stop_weak()
controller.rumble_stop_strong()

ControllerManager

为了简化控制器的热插拔, ControllerManager 课程是可用的。这个类有一个 get_controllers() 要用来代替的方法 pyglet.input.get_controllers() 。也有 on_connecton_disconnect 事件,每当连接或断开连接时都会调度一个控制器实例。首先,让我们回顾一下基本功能。

要使用ControllerManager,请首先创建一个实例::

manager = pyglet.input.ControllerManager()

然后,您可以从此实例查询当前连接的控制器。(如果未检测到控制器,则返回空列表)::

controllers = manager.get_controllers()

从列表中选择一个控制器并调用 Controller.open() 要打开它,请执行以下操作:

if controllers:
    controller = controllers[0]
    controller.open()

要处理控制器连接,请将处理程序附加到以下方法:

@manager.event
def on_connect(controller):
    print(f"Connected:  {controller}")

@manager.event
def on_disconnect(controller):
    print(f"Disconnected:  {controller}")

这些都是基础知识,并提供了在游戏中实现控制器热插拔所需的构建块。有关将这些概念结合在一起的示例,请参阅 examples/input/controller.py 在储存库中。

备注

如果您使用的是ControllerManager,则不应使用 pyglet.input.get_controllers() 直接去吧。结果是不确定的。使用 ControllerManager.get_controllers() 取而代之的是。

使用操纵杆

在使用操纵杆之前,你必须找到它并打开它。要获取当前连接到您的计算机的所有操纵杆设备的列表,请致电 pyglet.input.get_joysticks() **

joysticks = pyglet.input.get_joysticks()

然后从列表中选择一个操纵杆并拨打 Joystick.open 要打开设备::

if joysticks:
    joystick = joysticks[0]
    joystick.open()

操纵杆的当前位置被记录在其‘x’和‘y’属性中,这两个属性都被归一化为-1到1的范围内的值。对于x轴, x =-1表示将操纵杆完全推向左侧,并且 x =1表示将操纵杆推到右侧。对于y轴,值为 y =-1表示向上推操纵杆,值为 y =1表示按下操纵杆。如果存在其他轴,它们将被标记 zrxry ,或 rz

操纵杆按钮的状态包含在 buttons 属性作为布尔值的列表。True值表示相应的按钮正在被按下。虽然按钮在物理操纵杆上可能被标记为A、B、X或Y,但它们只是在访问时由其索引引用 buttons 单子。在不测试特定操纵杆的情况下,没有简单的方法可以知道哪个按钮索引对应于设备上的哪个物理按钮,所以让用户更改按钮分配是一个好主意。

每个打开的操纵杆在操纵杆改变状态时调度事件。对于按钮,有 on_joybutton_press() 每当按下操纵杆的任何按钮时发送的事件::

def on_joybutton_press(joystick, button):
    pass

以及 on_joybutton_release() 每当释放操纵杆的任何按钮时发送的事件::

def on_joybutton_release(joystick, button):
    pass

这个 Joystick 参数是 Joystick 实例的按钮更改了状态(如果连接了多个操纵杆,则非常有用)。这个 button 参数表示更改的是哪个按钮,它只是一个整数值,即 buttons 单子。

对于大多数游戏,最好直接使用 xy 属性。但是,如果希望在这些值发生更改时收到通知,则应处理 on_joyaxis_motion() 活动::

def on_joyaxis_motion(joystick, axis, value):
    pass

这个 Joystick 参数再次告诉您更改了哪个操纵杆设备。这个 axis 参数是诸如“x”、“y”或“rx”之类的字符串,告诉您哪个轴更改了值。和 value 给出轴的当前规格化值,范围在-1和1之间。

如果操纵杆有帽子开关,您可以通过查看 hat_xhat_y 属性。对于两者,值都是-1、0或1。请注意 hat_y 将在向上位置输出1,在向下位置输出-1,这与y轴控制相反。

要在HAT开关更改值时收到通知,请处理 on_joyhat_motion() 活动::

def on_joyhat_motion(joystick, hat_x, hat_y):
    pass

这个 hat_xhat_y 参数给出的值与操纵杆的值相同 hat_xhat_y 属性。

使用操纵杆事件处理程序的好方法可能是在控制器类中定义它们,然后调用::

joystick.push_handlers(my_controller)

请注意,您需要一个正在运行的应用程序事件循环,才能正确更新操纵杆按钮和轴值。请参阅 应用程序事件循环 部分,了解有关如何启动事件循环的更多详细信息。

使用Apple遥控器

Apple Remote是一款小型红外遥控器,最初是随iMac一起分发的。遥控器有六个按钮,可以通过名称访问这些按钮 leftrightupdownmenu ,以及 select 。此外,当按下某些按钮时,它们充当虚拟按钮。它们被命名为 left_holdright_holdmenu_hold ,以及 select_hold

要使用遥控器,请首先调用 get_apple_remote() **

remote = pyglet.input.get_apple_remote()

然后打开它::

if remote:
    remote.open(window, exclusive=True)

遥控器是在独占模式下打开的,因此当我们在程序中使用遥控器时,按下按钮不会激活计算机上的前排或更改音量等。

当遥控器上的按钮被按下或松开时,以下事件处理程序会告诉您:

def on_button_press(button):
    pass

def on_button_release(button):
    pass

这个 button 参数指示更改了哪个按钮,并且该字符串等于上面定义的十个按钮名称之一:“Up”、“Down”、“Left”、“Left_Hold”、“Right”、“Right_Hold”、“SELECT”、“SELECT_HOLD”、“MENU”或“MENU_HOLD”。

要使用遥控器,您可以在某个控制器类中定义事件处理程序的代码,然后调用::

remote.push_handlers(my_controller)

低电平设备

使用高级接口通常更容易,但对于专门的硬件,可以直接访问低级设备。您可以查询所有设备列表,并查看 name 属性以查找正确的设备::

for device in pyglet.input.get_devices():
    print(device.name)

确定要使用的设备后,您必须首先打开它::

device.open()

设备包含以下列表 Control 物体。有三种类型的控件: ButtonAbsoluteAxis ,以及 RelativeAxis 。为了帮助标识单个控件,每个控件至少有一个 name ,以及可选的 raw_name 属性。可以随时通过检查 Control.value 财产。此外,每个控件也是 EventDispatcher ,因此您也可以添加处理程序来接收更改。所有控件都会将 on_change 事件。按键也派送 on_presson_release 活动::

# All controls:

@control.event
def on_change(value):
    print("value:", value)

# Buttons:

@control.event
def on_press():
    print("button pressed")

@control.event
def on_release():
    print("button release")