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

游戏内鼠标录制回放脚本相机移动异常问题求助

3D游戏鼠标录制回放失效问题排查与解决建议

问题背景

我是速通游戏爱好者,为制作个人速通流程编写了Python脚本,用于录制游戏内键鼠输入并按时序回放。脚本基于pydirectinput和pynput库,通过pynput的监听器捕获on_move、on_press等事件,实现了F1启停录制、F2回放的功能——键盘输入回放正常,但3D游戏中相机移动回放完全失效,轨迹随机跳动。

已尝试的无效方案

  • 将光标固定在屏幕中心,使用pydirectinput.moveRel(x,y)模拟相对移动驱动相机,无效;
  • 限定鼠标活动窗口,触达边界时瞬移到另一侧模拟无限窗口,无效。

原因分析

  1. 绝对坐标与相对坐标的核心冲突:3D游戏的相机控制几乎都依赖**鼠标相对位移(delta)**而非绝对屏幕坐标,但当前脚本录制的是鼠标绝对位置,回放时直接调用moveTo会导致光标位置与游戏相机的映射逻辑完全错位——游戏实时读取的是鼠标移动的增量,而非最终停留位置。
  2. 系统级模拟的权限限制:部分全屏/独占模式的3D游戏会绕过系统消息队列,直接读取硬件输入,pydirectinput的常规模拟方法可能被游戏拦截,无法触发相机响应。
  3. 录制时的光标干扰:当前脚本在录制时限制光标活动范围,破坏了原始的鼠标位移数据,导致录制的delta信息不准确,进一步加剧回放偏差。

可行解决建议

1. 录制并回放鼠标相对位移(delta)

这是解决问题的核心:

  • 录制阶段:不再记录鼠标绝对坐标,而是计算相邻帧的位移差(dx, dy)作为事件数据;录制时将光标固定在屏幕中心并隐藏,避免边界限制打断位移记录。
  • 回放阶段:使用Windows底层API(如SendInput)直接模拟相对移动,绕过系统层面的输入拦截,确保游戏能捕获到真实的位移信号。

2. 优化游戏输入设置

  • 关闭游戏内的鼠标加速、平滑、灵敏度曲线等非线性设置,确保鼠标位移与相机转动成严格线性关系;
  • 若游戏支持,开启Raw Input模式,让游戏直接读取硬件输入,避免系统处理带来的模拟偏差。

3. 替换为更底层的输入模拟库

放弃pydirectinput的高层封装,直接使用pywin32调用SendInput或mouse_event,这类底层API对游戏独占模式的兼容性更好。

修改后的核心代码示例

调整录制逻辑(记录delta)

# 修改InputRecorder初始化
class InputRecorder:
    def __init__(self):
        # ... 原有代码 ...
        self.prev_x, self.prev_y = pydirectinput.position()

# 修改on_move函数
def on_move(x, y):
    global recorder
    if recorder.recording:
        # 计算相对位移
        dx = x - recorder.prev_x
        dy = y - recorder.prev_y
        recorder.record_event('delta', (dx, dy))
        recorder.prev_x, recorder.prev_y = x, y
        # 录制时固定光标在中心,防止触达边界
        pydirectinput.moveTo(recorder.center_x, recorder.center_y, _pause=False)

调整回放逻辑(用SendInput模拟相对移动)

# 在InputRecorder的replay_inputs方法中,替换delta分支的代码
elif event_type == 'delta':
    dx, dy = event_data
    # 调用Windows SendInput API模拟相对鼠标移动
    import ctypes
    INPUT_MOUSE = 0
    MOUSEEVENTF_MOVE = 0x0001

    class POINT(ctypes.Structure):
        _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_long)]

    class INPUT(ctypes.Structure):
        class _INPUT(ctypes.Union):
            class _MOUSEINPUT(ctypes.Structure):
                _fields_ = [("dx", ctypes.c_long), ("dy", ctypes.c_long),
                            ("mouseData", ctypes.c_ulong), ("dwFlags", ctypes.c_ulong),
                            ("time", ctypes.c_ulong), ("dwExtraInfo", ctypes.POINTER(ctypes.c_ulong))]
            _fields_ = [("mi", _MOUSEINPUT)]
        _anonymous_ = ("_input",)
        _fields_ = [("type", ctypes.c_ulong), ("_input", _INPUT)]
    
    extra = ctypes.c_ulong(0)
    input_mouse = INPUT()
    input_mouse.type = INPUT_MOUSE
    # 将相对位移转换为SendInput要求的绝对坐标比例(范围-32768到32767)
    input_mouse.mi.dx = dx * 65536 // recorder.screen_width
    input_mouse.mi.dy = dy * 65536 // recorder.screen_height
    input_mouse.mi.dwFlags = MOUSEEVENTF_MOVE
    input_mouse.mi.dwExtraInfo = ctypes.pointer(extra)
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_mouse), ctypes.sizeof(input_mouse))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 14:15:56