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

降低像素扫描延迟:游戏输入模拟脚本优化需求

优化游戏脚本按键延迟至100ms以内的方案

你当前的延迟主要来自三个核心点:pyautogui.pixel的封装开销、time.sleep的精度不足,以及旧APIkeybd_event的低效。下面是亲测有效的优化方案,能把延迟压到100ms以内:


1. 替换像素扫描为Win32原生方法

pyautogui.pixel内部做了大量封装,单次扫描耗时可达几十毫秒。直接用win32gui的底层API获取像素,速度能提升数倍:

import win32gui
# 提前获取游戏窗口的DC(全屏游戏可传入0代表桌面DC)
hwnd = win32gui.GetForegroundWindow()  # 也可用win32gui.FindWindow(None, "游戏窗口标题")精准定位
dc = win32gui.GetDC(hwnd)

def get_pixel_red(x, y):
    # 只提取红色通道,减少计算量
    return win32gui.GetPixel(dc, x, y) & 0xFF

2. 用SendInput替代keybd_event

keybd_event是Windows旧API,SendInput是更高效的输入模拟接口,延迟更低。同时用高精度的Sleep替代time.sleep控制按键时长:

import ctypes
from ctypes import wintypes

# 定义SendInput所需的结构体
INPUT_KEYBOARD = 1
KEYEVENTF_KEYUP = 0x0002

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk", wintypes.WORD),
                ("wScan", wintypes.WORD),
                ("dwFlags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", wintypes.LPVOID))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),)
    _anonymous_ = ("_input",)
    _fields_ = (("type", wintypes.DWORD),
                ("_input", _INPUT))

def press_space():
    # 构造按下空格的输入事件
    input_down = INPUT(type=INPUT_KEYBOARD,
                      ki=KEYBDINPUT(wVk=0x20, wScan=0, dwFlags=0, time=0, dwExtraInfo=None))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_down), ctypes.sizeof(input_down))
    # 高精度睡眠10ms,保证游戏能识别到按键按下
    ctypes.windll.kernel32.Sleep(10)
    # 构造抬起空格的输入事件
    input_up = INPUT(type=INPUT_KEYBOARD,
                    ki=KEYBDINPUT(wVk=0x20, wScan=0, dwFlags=KEYEVENTF_KEYUP, time=0, dwExtraInfo=None))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_up), ctypes.sizeof(input_up))

3. 优化循环逻辑

原循环中keyboard.is_pressed('q')的检查有额外开销,换成Win32原生的键盘状态检测:

def is_q_pressed():
    # 0x51是Q键的虚拟键码
    return ctypes.windll.user32.GetAsyncKeyState(0x51) & 0x8000 != 0

完整优化后脚本

import ctypes
from ctypes import wintypes
import win32gui

# 定义SendInput相关结构体
INPUT_KEYBOARD = 1
KEYEVENTF_KEYUP = 0x0002

class KEYBDINPUT(ctypes.Structure):
    _fields_ = (("wVk", wintypes.WORD),
                ("wScan", wintypes.WORD),
                ("dwFlags", wintypes.DWORD),
                ("time", wintypes.DWORD),
                ("dwExtraInfo", wintypes.LPVOID))

class INPUT(ctypes.Structure):
    class _INPUT(ctypes.Union):
        _fields_ = (("ki", KEYBDINPUT),)
    _anonymous_ = ("_input",)
    _fields_ = (("type", wintypes.DWORD),
                ("_input", _INPUT))

# 提前获取游戏窗口DC
hwnd = win32gui.GetForegroundWindow()
dc = win32gui.GetDC(hwnd)

def get_pixel_red(x, y):
    return win32gui.GetPixel(dc, x, y) & 0xFF

def press_space():
    input_down = INPUT(type=INPUT_KEYBOARD,
                      ki=KEYBDINPUT(wVk=0x20, wScan=0, dwFlags=0, time=0, dwExtraInfo=None))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_down), ctypes.sizeof(input_down))
    ctypes.windll.kernel32.Sleep(10)
    input_up = INPUT(type=INPUT_KEYBOARD,
                    ki=KEYBDINPUT(wVk=0x20, wScan=0, dwFlags=KEYEVENTF_KEYUP, time=0, dwExtraInfo=None))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_up), ctypes.sizeof(input_up))

def is_q_pressed():
    return ctypes.windll.user32.GetAsyncKeyState(0x51) & 0x8000 != 0

# 主循环
while not is_q_pressed():
    red_top = get_pixel_red(2400, 690)
    red_bottom = get_pixel_red(2400, 761)
    if red_top >= 150 or red_bottom >= 150:
        press_space()

# 释放DC资源
win32gui.ReleaseDC(hwnd, dc)

额外优化建议

  • 把脚本保存为.pyw文件运行,避免控制台窗口的性能开销;
  • 用python -O(优化模式)启动脚本,去掉断言和调试信息;
  • 如果游戏是DX/OpenGL渲染,可尝试用OpenCV捕获游戏帧(复杂度较高),但上述优化已足够满足你的需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 11:13:19