You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Arcade及Pyglet环境下游戏摇杆/手柄无法正常检测的问题求助

Python Arcade 游戏控制器检测异常问题

故障环境与表现

故障复现环境为2台搭载Windows10系统、运行Python3的设备,测试设备包含2款非官方有线Xbox360手柄、1款微软官方无线Xbox360手柄,所有测试场景表现完全一致:

  • 仅在手柄刚插入的瞬间,arcade.get_joysticks()会短暂返回非空结果,随即返回空列表
  • 程序启动时手柄已经处于连接状态,调用接口同样返回空列表
  • 官方摇杆示例、自行编写的精简Pyglet测试脚本均复现相同问题:加入sleep延时的脚本完全无法识别手柄;无延时的无限循环检测脚本仅在手柄插拔瞬间短暂返回Joystick对象,之后立刻返回空列表
  • 测试全程手柄保持物理连接、硬件功能正常

测试代码与运行输出

初始控制器测试模块(tq_menu)

# tq_menu
import arcade

class CursorControl():
    joystick_count = len(arcade.get_joysticks())
    def on_step(self):
        if (self.joystick_count != len(arcade.get_joysticks())):
            print("Joystick count changed")
        print(f"Joy count is: {self.joystick_count}")

controller__cursor = CursorControl()

首次运行时程序可短暂识别手柄插入事件,后续测试该功能完全失效。

主游戏测试逻辑

import tq_menu
import arcade
import pyglet

class MainGame(arcade.Window):
    def __init__(self):
        super().__init__(600, 600, title="Test Game")
        self.update_tick_count = 0
        print("Initial: " + str(arcade.get_game_controllers()))

    def on_update(self, delta_time):
        self.update_tick_count += 1
        if (self.update_tick_count % 60 == 0): self.on_update_second()
    
    def on_update_second(self):
        # 约每秒调用一次
        print(pyglet.input.get_joysticks())
        print("Before: " + str(arcade.get_game_controllers()))
        print("1 sec")
        tq_menu.controller__cursor.on_step()

手柄保持连接状态下的程序运行输出:

Initial: []
[]
Before: []
1 sec
Joy count is: 0
[]
Before: []
1 sec
Joy count is: 0
[<pyglet.input.base.Joystick object at 0x000001D677DC9E40>]
Before: []
1 sec
Joy count is: 0
[]
Before: []
1 sec
Joy count is: 0

精简Pyglet验证脚本

import pyglet
import time

while True:
    joysticks = pyglet.input.get_joysticks()
    print(joysticks)
    #time.sleep(0.5)

脚本运行输出:

[] <- 启动时手柄已插入,初始返回空
[]
[]
[]
[]
[]
[]
[]
[]
[] <- 此处拔下手柄
[]
[]
[]
[]
[]
[<pyglet.input.base.Joystick object at 0x000001F7992877F0>] <- 此处插回手柄
[]
[]
[]
[]
[]
[] <- 此处再次拔下手柄
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[<pyglet.input.base.Joystick object at 0x000001F79AD49CF0>] <- 此处重新插入手柄
[]
[]
[]
[]
[]
[]

修复方案

  • 升级依赖到兼容版本:执行pip install --upgrade arcade pyglet,将Arcade升级到2.6.17以上、Pyglet升级到2.0.10以上版本。旧版本Pyglet在Windows平台存在即插即用设备枚举后被自动回收的已知bug,会导致枚举到的Joystick对象瞬间失效,接口返回空列表。
  • 调整设备枚举时机:禁止在类属性定义、模块加载阶段调用get_joysticks()/get_game_controllers()获取设备列表,必须在Window实例初始化完成、Pyglet事件循环启动后再做枚举。模块加载阶段Pyglet的输入设备管理器还未完成初始化,此时拿到的设备列表完全无效,这也是测试代码中CursorControl类的joystick_count值始终为0的核心原因。
  • 枚举到手柄对象后必须手动持有引用并打开设备:不能只临时调用接口拿列表就直接使用,没有被引用的Joystick对象会被Python垃圾回收机制自动释放,后续接口就会返回空。正确的初始化逻辑参考:
class MainGame(arcade.Window):
    def __init__(self):
        super().__init__(600, 600, title="Test Game")
        self.connected_joysticks = []
        # 窗口初始化完成后再枚举设备
        controllers = arcade.get_game_controllers()
        for ctrl in controllers:
            ctrl.open() # 必须调用open打开设备,持有系统设备句柄
            self.connected_joysticks.append(ctrl)
  • 修正设备检测逻辑:不要脱离Arcade/Pyglet主事件循环,在独立死循环里调用get_joysticks()做检测。这种写法不会运行Pyglet的系统事件泵,无法正常处理设备插拔事件,只能在插拔瞬间拿到临时设备对象。设备检测逻辑必须放在Window的on_update等主循环回调中执行。
  • 驱动与后端适配:Xbox360手柄在Windows10上直接使用系统自带的XInput驱动即可,不要安装第三方老旧的DirectInput版360手柄驱动,这类驱动会和Pyglet的枚举逻辑冲突,导致设备识别后立刻掉线。如果升级依赖后仍存在识别问题,可在代码最开头强制指定Pyglet使用XInput后端枚举手柄,绕过DirectInput的枚举bug:
import pyglet
pyglet.options["win32_xinput"] = True
import arcade

内容的提问来源于stack exchange,提问作者Pogmog

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 20:24:09