请求:捕获第一人称3D游戏内鼠标移动用于强化学习行为克隆
解决3D游戏内鼠标位移捕获问题(用于行为克隆数据采集)
问题核心在于:多数第一人称3D游戏会锁定系统光标在窗口中心并隐藏,pyautogui/mouse这类工具读取的是系统层面的光标绝对位置,自然捕获不到实际的鼠标移动——因为系统光标根本没动,游戏内部直接读取的是鼠标的原始相对位移(delta值)。
下面是几个可行的解决方向:
1. 调用系统原始输入API(Windows平台)
直接读取Windows的Raw Input数据,绕过系统光标位置,获取鼠标的原生位移。用Python的ctypes就能实现,无需额外第三方库:
import ctypes from ctypes import wintypes # 定义Windows API所需的结构体和常量 user32 = ctypes.WinDLL('user32', use_last_error=True) RAWINPUTDEVICE = wintypes.STRUCTURE class RAWINPUTDEVICE(RAWINPUTDEVICE): _fields_ = [("usUsagePage", wintypes.WORD), ("usUsage", wintypes.WORD), ("dwFlags", wintypes.DWORD), ("hwndTarget", wintypes.HWND)] RAWINPUTHEADER = wintypes.STRUCTURE class RAWINPUTHEADER(RAWINPUTHEADER): _fields_ = [("dwType", wintypes.DWORD), ("dwSize", wintypes.DWORD), ("hDevice", wintypes.HANDLE), ("wParam", wintypes.WPARAM)] RAWMOUSE = wintypes.STRUCTURE class RAWMOUSE(RAWMOUSE): _fields_ = [("usFlags", wintypes.WORD), ("ulButtons", wintypes.DWORD), ("usButtonFlags", wintypes.WORD), ("usButtonData", wintypes.WORD), ("ulRawButtons", wintypes.DWORD), ("lLastX", wintypes.LONG), ("lLastY", wintypes.LONG), ("ulExtraInformation", wintypes.DWORD)] RAWINPUT = wintypes.STRUCTURE class RAWINPUT(RAWINPUT): _fields_ = [("header", RAWINPUTHEADER), ("mouse", RAWMOUSE)] RID_INPUT = 0x10000003 def register_raw_input(): rid = RAWINPUTDEVICE() rid.usUsagePage = 0x01 rid.usUsage = 0x02 # 鼠标设备 rid.dwFlags = 0 rid.hwndTarget = None if not user32.RegisterRawInputDevices(ctypes.byref(rid), 1, ctypes.sizeof(rid)): raise ctypes.WinError(ctypes.get_last_error()) def get_mouse_delta(): data_size = wintypes.DWORD() user32.GetRawInputBuffer(None, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER)) buffer = ctypes.create_string_buffer(data_size.value) num_events = user32.GetRawInputBuffer(buffer, ctypes.byref(data_size), ctypes.sizeof(RAWINPUTHEADER)) delta_x, delta_y = 0, 0 for i in range(num_events): raw_input = ctypes.cast(buffer + i * data_size.value, ctypes.POINTER(RAWINPUT)) if raw_input.contents.header.dwType == 0: # 鼠标输入 delta_x += raw_input.contents.mouse.lLastX delta_y += raw_input.contents.mouse.lLastY return delta_x, delta_y # 示例用法 if __name__ == "__main__": register_raw_input() while True: dx, dy = get_mouse_delta() if dx != 0 or dy != 0: print(f"鼠标位移: X={dx}, Y={dy}")
这段代码会直接捕获鼠标的原生相对位移,不受游戏光标锁定的影响。
2. 利用游戏引擎内置API(如果有权限访问引擎)
如果目标游戏是用Unity/Unreal等引擎开发的,直接在引擎内编写脚本捕获输入是最可靠的方式:
- Unity:在Update函数中用
Input.GetAxis("Mouse X")和Input.GetAxis("Mouse Y")获取帧间位移,然后将数据写入文件。 - Unreal:在PlayerController的Tick函数中读取
GetInputMouseDelta(X, Y),保存位移数据。
这种方式能直接拿到游戏内部使用的鼠标输入数据,完全避免系统层面的兼容性问题。
3. 内存读取(进阶方案,谨慎使用)
如果无法访问游戏引擎,可以尝试读取游戏进程内存中存储鼠标位移的变量。但这个方法需要逆向分析游戏内存结构,且可能触发反作弊系统,仅适合非线上游戏或有开发权限的场景。
内容的提问来源于stack exchange,提问作者Snykral fa Ashama
相关产品推荐
相关产品推荐

