URLhttps://learnscript.net/zh/pygame/event/controller/
    复制链接转到说明  示例

    如何处理游戏中的控制器事件

    我被代码海扁署名-非商业-禁演绎
    阅读 13:29·字数 4048·更新 

    虽然本节所提到的内容与事件有关,但捕获事件的方法,请参考如何捕获处理游戏事件?以及创建和引发自定义事件等问题一节。除了通过事件,你也可以使用joystick模块来实现与控制器相关的功能,具体请查看如何获取控制器的信息和状态(按键状态,方向键状态,轴状态等)一节。

    初始化 joystick 模块

    要在 Pygame 中处理与控制器相关的事件,你需要首先对joystick模块进行初始化,否则相关代码可能不会执行。此外,类似于按键按下和释放,轴和轨迹球移动等事件,还需要创建和保持与控制器相关的JoystickType对象。

    控制器

    关于初始化joystick模块,你可以查看初始化 joystick 模块一段。

    连接和中断连接事件

    pygame模块拥有变量JOYDEVICEADDED,表示游戏控制器的连接事件,该事件可能在游戏中接入新的控制器时引发,也可能在游戏启动时引发(如果已经在启动前连接了控制器),其对应的Event对象拥有以下变量。

    device_index 变量

    device_index变量是一个整数,其含义为控制器的设备索引,通常用于创建JoystickType对象。设备索引可被理解为控制器的顺序,同一个控制器的设备索引可能会发生改变,当连接了新的控制器或原有控制器中断连接时。因此,device_index变量仅在控制器连接事件中保证其准确性。

    guid 变量

    guid变量是一个 GUID 字符串,用于标识某种控制器型号。由于该字符串只是针对型号,因此,他不能用于标识每一个游戏控制器,当你链接同一品牌的同种型号的两个控制器时,他们将拥有相同的 GUID。

    pygame模块拥有变量JOYDEVICEREMOVED,表示游戏控制器的中断连接事件,此事件对应的Event对象拥有以下变量。

    instance_id 变量

    instance_id变量是一个表示实例 ID 的整数,实例 ID 可用于唯一的标识控制器。

    游戏控制器的实例 ID 与创建 JoystickType 对象无关

    对于每一个新连接的控制器,Pygame 都会为其分配一个实例 ID,该实例 ID 与是否创建JoystickType对象或创建多少个JoystickType对象无关。这意味着,对于同一个控制器,创建与其相关的多个JoystickType对象,并不会改变该控制器的实例 ID。

    重新连接游戏控制器,其实例 ID 可能会发生变化

    对于同一个控制器,如果在中断连接后重新连接,那么其对应的实例 ID 可能会发生变化。

    在下面的示例中,我们通过一个列表来保持通过设备索引创建的JoystickType对象,并根据实例 ID 将无用的JoystickType对象从列表中移除。

    connection.py
    # 导入相关内容,创建游戏窗口,初始化模块
    from pygame import display, event, joystick, QUIT
    display.set_mode((800, 600))
    joystick.init()
    
    # 导入与控制器事件相关的变量 from pygame import JOYDEVICEADDED, JOYDEVICEREMOVED # 保存 JoystickType 对象的列表 jss = []
    running = True while running: for e in event.get(): if e.type == QUIT: running = False elif e.type == JOYDEVICEADDED: # 根据设备索引创建 JoystickType 对象,并添加至 jss js = joystick.Joystick(e.device_index) jss.append(js)
    print('添加控制器', e.device_index) elif e.type == JOYDEVICEREMOVED: # 根据实例 ID,将 JoystickType 对象从 jss 移除 for js in jss: if js.get_instance_id() == e.instance_id: jss.remove(js) print('移除控制器', e.instance_id) break

    按键的按下和释放事件

    pygame模块拥有变量JOYBUTTONDOWNJOYBUTTONUP,他们分别表示控制器按键被按下和释放的事件,事件所对应Event对象拥有以下变量。

    instance_id 变量

    instance_id变量是表示控制器实例 ID 的整数,他将指示引发事件的具体控制器。

    button 变量

    button变量是一个整数,用于表示控制器上被按下或释放的按键。

    控制器按键被按下的事件不会被连续引发

    一般情况下,控制器按键被按下的事件不会被连续引发,即便将某个控制器按键保持按下状态,按键按下的事件也仅会引发一次。不过,某些型号的控制器可能会拥有自动连发功能,如果开启此功能并保持按键的按下状态,那么按键的按下事件和释放事件会被连续引发。

    在下面的示例中,我们通过字典来保持JoystickType对象,字典的键为控制器的实例 ID。在控制器的按键按下事件中,可根据事件传递的实例 ID 在字典中找到玩家索引。

    button.py
    # 导入并初始化相关模块,创建游戏窗口
    from pygame import display, event, joystick, JOYDEVICEADDED
    display.set_mode((800, 600))
    joystick.init()
    
    # 导入与控制器事件相关的变量 from pygame import JOYBUTTONDOWN, JOYBUTTONUP # 保存控制器信息的字典 cs = {} # 玩家索引 playerIndex = 0
    running = True while running: for e in event.get(): if e.type == JOYDEVICEADDED: js = joystick.Joystick(e.device_index)
    # 将 JoystickType 对象与玩家索引添加至字典,实例 ID 为键 playerIndex += 1 cs[js.get_instance_id()] = [js, playerIndex] elif e.type == JOYBUTTONDOWN: # 根据实例 ID 获取字典中的控制器信息,显示玩家索引 c = cs[e.instance_id]
    print(f'玩家 {c[1]} 按下了 {e.button}') elif e.type == JOYBUTTONUP: # 如果释放了开始键,则游戏结束 if e.button == 7: running = False

    方向键(十字键)事件

    pygame模块拥有变量JOYHATMOTION,他表示控制器方向键(十字键)被操作的事件(按下和释放均会引发),该事件所对应Event对象拥有以下变量。

    instance_id 变量

    instance_id变量是表示控制器实例 ID 的整数,他将指示引发事件的具体控制器。

    hat 变量

    hat变量是表示方向键 ID 的整数,可用于指示引发事件的具体方向键,大部分情况下该变量为0(拥有多个方向键的控制器非常罕见)。

    value 变量

    value变量是一个形式为(x,y)的整数元组。如果x1,则表示右方向键被按下,为-1,则表示左方向键被按下。如果y1,则表示上方向键被按下,为-1,则表示下方向键被按下。

    控制器的方向键事件不会被连续引发

    一般情况下,控制器的方向键事件不会被连续引发,即便将方向键保持按下状态,因按下而引发的事件也仅会出现一次。

    某些控制器的方向键不会引发方向键事件

    并非所有控制器的方向键均会引发方向键事件,某些控制器的方向键会引发按键按下和按键释放事件(JOYBUTTONDOWNJOYBUTTONUP)。

    在下面的示例中,我们根据事件对象的value变量,获取方向键的按下状态,以决定游戏角色向哪个方向移动。

    hat.py
    # 导入并初始化相关模块,创建游戏窗口
    from pygame import display, event, joystick, JOYDEVICEADDED, QUIT
    display.set_mode((800, 600))
    joystick.init()
    
    # 导入与控制器事件相关的变量 from pygame import JOYHATMOTION # 保存 JoystickType 对象的列表 jss = [] # 表示水平和垂直的移动方向 h = 0 v = 0
    running = True while running: for e in event.get(): if e.type == QUIT: running = False elif e.type == JOYDEVICEADDED: jss.append(joystick.Joystick(e.device_index)) elif e.type == JOYHATMOTION: # 获取十字键的按下状态 (x, y) = e.value
    # 根据十字键的按下状态,设置游戏角色的移动方向 if x == 1: h = 1 print('开始向右移动') elif x == -1: h = -1 print('开始向左移动') elif h != 0: h = 0 print('取消水平移动')
    if y == 1: v = 1 print('开始向上移动') elif y == -1: v = -1 print('开始向下移动') elif v != 0: v = 0 print('取消垂直移动')

    轴(摇杆,扳机键)移动事件

    游戏控制器一般拥有一些轴装置,最为常见的是摇杆和扳机键。pygame模块的变量JOYAXISMOTION,可用于表示轴的移动事件,该事件所对应Event对象拥有以下变量。

    instance_id 变量

    instance_id变量是表示控制器实例 ID 的整数,他将指示引发事件的具体控制器。

    axis 变量

    axis变量是表示轴 ID 的整数,可用于指示引发事件的具体轴。

    大部分的游戏控制器均拥有左右两个摇杆和左右两个扳机键,当axis02时,事件通常由左摇杆或右摇杆在水平方向上的移动引发,当axis13时,事件通常由左摇杆或右摇杆在垂直方向上的移动引发,当axis45时,事件通常由左扳机键或右扳机键引发。

    需要指出的是,不同型号的控制器,其类似的轴装置的 ID 可能会不同,axis3并不表示事件一定由右摇杆在垂直方向上的移动引发。

    value 变量

    value变量是一个浮点数,表示了轴(摇杆,扳机键)与中心之间的距离,其取值范围从-11,等于0表示轴(摇杆,扳机键)位于中心位置,等于(或接近于)-11表示轴(摇杆,扳机键)已到达边缘最大位置。当axis02时,value通常表示摇杆与中心之间的水平距离(-1为左边最大位置,1为右边最大位置)。当axis13时,value通常表示摇杆与中心之间的垂直距离(-1为上边最大位置,1为下边最大位置)。

    对于摇杆而言,value变量的默认值理论上为0,对于扳机键而言,value变量的默认值理论上为-1

    axis.py
    # 导入并初始化相关模块,创建游戏窗口
    from pygame import display, event, joystick, JOYDEVICEADDED, QUIT
    display.set_mode((800, 600))
    joystick.init()
    
    # 导入与控制器事件相关的变量 from pygame import JOYAXISMOTION # 保存 JoystickType 对象的列表 jss = []
    running = True while running: for e in event.get(): if e.type == QUIT: running = False elif e.type == JOYDEVICEADDED: jss.append(joystick.Joystick(e.device_index)) elif e.type == JOYAXISMOTION: # 判断触发事件的轴装置是否为右扳机键 if e.axis == 5: # 判断右扳机键的移动程度,是否足以发动攻击 if e.value > -0.3: print('攻击') else: print('停止攻击')

    轨迹球滚动事件

    针对射击游戏,一些游戏控制器可能会设计轨迹球,其操作效果类似于鼠标。pygame模块的变量JOYBALLMOTION,可用于表示轨迹球的滚动事件,该事件所对应Event对象拥有以下变量。

    instance_id 变量

    instance_id变量是表示控制器实例 ID 的整数,他将指示引发事件的具体控制器。

    ball 变量

    ball变量是表示轨迹球 ID 的整数,可用于指示引发事件的具体轨迹球。

    rel 变量

    rel变量是一个形式类似于(x,y)的 Python 整数元组,表示与上一次事件相比,轨迹球的移动距离,其中x表示水平移动距离,y表示垂直移动距离。

    源码

    src/zh/event/controller·codebeatme/pygame·GitHub

    讲解视频

    如何在 Pygame 中处理控制器的连接和中断事件·YouTube如何在 Pygame 中处理控制器的连接和中断事件·Bilibili
    如何在 Pygame 中处理控制器的按键事件·YouTube如何在 Pygame 中处理控制器的按键事件·Bilibili
    如何在 Pygame 中处理控制器的方向键事件·YouTube如何在 Pygame 中处理控制器的方向键事件·Bilibili
    如何在 Pygame 中处理控制器的摇杆移动事件·YouTube如何在 Pygame 中处理控制器的摇杆移动事件·Bilibili