基于计算机视觉的游戏AI开发:Agent of Empires框架实战解析

张开发
2026/5/12 1:44:37 15 分钟阅读

分享文章

基于计算机视觉的游戏AI开发:Agent of Empires框架实战解析
1. 项目概述一个面向帝国时代系列游戏的AI智能体框架最近在游戏AI和自动化测试的圈子里一个名为“Agent of Empires”的项目引起了我的注意。这个由njbrake开源的框架其核心目标直指一个非常具体且充满挑战的领域为《帝国时代》系列即时战略游戏构建一个通用的、可编程的AI智能体。简单来说它不是一个用来“玩游戏”的外挂而是一个强大的开发工具包允许开发者、研究者和爱好者通过编写Python脚本来模拟人类玩家的操作实现从基础资源采集到复杂战术调度的全流程自动化。这个项目解决的痛点非常明确。对于《帝国时代》这类复杂的RTS游戏传统的脚本录制或简单的宏操作早已无法满足深度研究的需求。无论是进行游戏平衡性的大规模模拟测试还是研究多智能体协作的学术课题亦或是想为自己喜欢的游戏打造一个独特的“电脑对手”都需要一个能够精准控制游戏单位、读取游戏状态、并做出复杂决策的接口。Agent of Empires正是为此而生它通过计算机视觉和模拟输入技术搭建了一座连接外部代码与游戏世界的桥梁让程序能够“看见”屏幕、“理解”局势并“操作”鼠标键盘来执行策略。它适合几类人一是游戏开发者或测试工程师可以用它来进行自动化压力测试和平衡性验证二是人工智能和机器学习的研究者可以将其作为一个绝佳的、高复杂度的强化学习环境三是硬核的游戏爱好者和模组制作者能够用它来创造独一无二的AI对手或实现复杂的自动化流程。接下来我将深入拆解这个项目的设计思路、核心技术栈、实操搭建过程以及那些在官方文档里不会写的“踩坑”经验。2. 框架核心架构与设计哲学解析2.1 非注入式交互安全与兼容性的基石Agent of Empires 最核心的设计选择也是它区别于许多游戏机器人的关键在于其严格采用非注入式Non-Invasive的外部交互方式。这意味着框架不会向游戏进程注入任何DLL动态链接库不修改游戏内存也不拦截网络封包。它的所有交互都建立在模拟一个“坐在电脑前的真实玩家”这一基础上。为什么选择这条看起来更“笨拙”的路原因有三。第一是绝对的安全性。任何内存修改或代码注入行为都极易被现代游戏的反作弊系统如《帝国时代2决定版》使用的反作弊保护检测并封禁。非注入式方法只操作外设输入和读取屏幕像素从游戏客户端的视角看与真人操作无异极大降低了被封号的风险。第二是卓越的兼容性。由于不依赖特定的游戏内存结构或函数地址该框架理论上可以兼容不同版本的游戏甚至经过适当适配可以扩展到其他类似的RTS游戏。第三是降低了开发门槛。开发者无需掌握复杂的逆向工程知识只需关注高层策略逻辑而将底层的图像识别和输入模拟交给框架处理。这种设计哲学决定了框架的三大核心模块视觉感知模块Vision、决策逻辑模块Brain和动作执行模块Actuator。视觉模块负责从游戏截图中提取结构化信息如资源数量、单位位置、建筑状态决策模块是用户编写的Python AI逻辑动作模块则将决策转化为具体的鼠标移动、点击和键盘按键序列。2.2 模块化与可扩展性设计项目的代码结构充分体现了模块化的思想。核心的交互逻辑被抽象成独立的服务或类例如ScreenCapturer: 负责以高频率捕获游戏窗口的指定区域。TemplateMatcher: 基于OpenCV进行模板匹配用于在画面中寻找特定的图标如资源图标、单位头像、按钮。StateInterpreter: 将匹配到的视觉元素转化为有意义的游戏状态数据例如通过识别小地图上的色块来判定敌方单位聚集区域。ActionExecutor: 一个封装了pyautogui或pydirectinput的模块负责以可配置的延迟和随机性执行点击和按键操作。这种模块化带来的最大好处是可替换性和可扩展性。如果你觉得默认的模板匹配算法在某种画面下不准可以轻松替换成基于深度学习的YOLO目标检测模型。如果你需要控制多显示器或特定虚拟机内的游戏可以重写ScreenCapturer。决策大脑更是完全由用户掌控可以从简单的有限状态机FSM到复杂的神经网络决策器。3. 环境搭建与核心配置实战3.1 基础环境准备Python与依赖库首先你需要一个Python环境建议3.8及以上版本。项目依赖的核心库包括opencv-python用于图像处理和模板匹配。numpyOpenCV的伴侣处理图像矩阵。pyautogui跨平台的GUI自动化库用于控制鼠标和键盘。pillow图像处理库有时用于截图。pydirectinput(可选)一个尝试提供更底层、更直接的输入控制的库在某些游戏中对pyautogui是更好的补充。你可以通过pip一键安装pip install opencv-python numpy pyautogui pillow pydirectinput。这里有个关键细节不同版本的OpenCV可能在某些图像处理函数上有细微差异建议锁定一个稳定版本例如opencv-python4.5.5.64以避免后续脚本因版本问题而失效。3.2 游戏端关键设置为视觉识别铺路要让AI“看”得清“操作”得准游戏本身的设置至关重要。以下是我经过多次测试总结出的《帝国时代2决定版》最优配置方案图形设置分辨率固定为1920x10801080P。这是模板图片制作的基准分辨率改变分辨率会导致所有模板匹配失效。显示模式必须使用独占全屏Fullscreen Exclusive或无边框窗口化Borderless Windowed。避免使用普通的窗口化模式因为窗口边框和标题栏会干扰屏幕坐标的计算。无边框窗口化是首选便于切换调试。图形预设设置为最低Lowest。这并非为了性能而是为了视觉识别的稳定性。高画质下的阴影、光影效果、植被细节会严重干扰基于颜色和形状的模板匹配。最低画质能提供最“干净”、对比度最高的界面元素。关闭所有后期处理如景深、动态模糊、晕影等一律关闭。界面设置UI缩放保持默认100%。任何UI缩放都会改变图标和按钮的实际像素尺寸导致模板匹配失败。小地图建议设置为“已探索区域始终可见”并调至最大尺寸。这能让AI更清晰地感知全局态势。单位生命值条设置为“始终显示”。这对于判断单位战斗状态至关重要。操作设置将“空闲村民”快捷键改为一个不常用的键如“”。因为AI会频繁使用编队和选择操作避免与游戏默认的寻找空闲村民快捷键冲突。3.3. 项目初始化与模板图像采集克隆项目仓库后你会发现一个templates/或assets/目录。这里存放的就是框架的“眼睛”——用于匹配的模板图片。官方可能提供一些基础模板但要想AI工作良好自制模板是必不可少的一步。模板制作黄金法则纯净截图在游戏处于前述最优设置下对需要识别的UI元素如“建造城镇中心”按钮、食物图标、黄金图标进行截图。使用Windows自带的“截图工具”Snipping Tool并确保模式为“矩形截图”精准框选目标不留多余像素。统一命名使用清晰、有意义的英文命名如button_town_center.png,icon_food.png,icon_wood.png。尺寸适中模板不宜过大增加计算量或过小降低匹配精度。通常按钮图标在30x30到50x50像素之间资源图标在20x20左右。灰度化处理在代码中模板和屏幕截图通常会先被转换为灰度图再进行匹配以减少颜色变化的干扰。因此制作模板时无需过分担心颜色但要保证形状和明暗对比清晰。一个高级技巧是对于状态会变化的图标如“生产队列繁忙”和“空闲”可以制作多个模板或者通过检测图标特定区域的颜色如生产队列进度条的颜色来进行更精细的状态判断。4. 核心模块深度剖析与脚本编写4.1 视觉感知模块从像素到信息视觉模块是AI的感官。其工作流程通常是截图 - 预处理 - 模板匹配 - 坐标解析。import cv2 import numpy as np import pyautogui class VisionAgent: def __init__(self, template_paths): self.templates {name: cv2.imread(path, cv2.IMREAD_GRAYSCALE) for name, path in template_paths.items()} def find_on_screen(self, template_name, threshold0.8): # 截取整个屏幕或游戏区域 screenshot pyautogui.screenshot() screenshot_gray cv2.cvtColor(np.array(screenshot), cv2.COLOR_RGB2GRAY) template self.templates[template_name] w, h template.shape[::-1] # 获取模板宽高 # 使用模板匹配 res cv2.matchTemplate(screenshot_gray, template, cv2.TM_CCOEFF_NORMED) loc np.where(res threshold) points [] for pt in zip(*loc[::-1]): # 切换列和行 points.append((pt[0] w//2, pt[1] h//2)) # 返回图标中心点坐标 return points # 返回所有匹配到的中心点坐标列表关键参数与避坑指南threshold置信度阈值这是最关键的参数。阈值设得过高如0.95可能会漏检设得过低如0.6会产生大量误检。必须针对每个模板进行单独调试。调试时可以写一个循环实时打印当前屏幕下某个模板的匹配最高分观察其在各种游戏画面下的波动情况从而确定一个合理的阈值。匹配方法cv2.TM_CCOEFF_NORMED是常用且效果较好的方法它对光照变化有一定鲁棒性。如果游戏界面明暗变化剧烈可以尝试cv2.TM_SQDIFF_NORMED。性能优化全屏匹配非常耗时。如果知道目标UI元素的大致区域如资源数字总在屏幕上方可以只截取屏幕的特定区域ROI进行匹配能极大提升帧率。4.2 动作执行模块模拟人类操作动作模块负责将决策坐标转化为操作。这里模拟人类的“不精确性”和“延迟”是避免被检测的关键。import random import time from pydirectinput import moveTo, click, press # 有时比pyautogui更可靠 class ActionAgent: def __init__(self): self.operation_delay (0.05, 0.15) # 每次操作后的随机延迟区间 self.move_duration (0.1, 0.3) # 鼠标移动的随机耗时区间 def human_click(self, x, y, buttonleft): # 1. 加入随机移动路径可选更拟真 # 2. 以随机速度移动鼠标 moveTo(x, y, durationrandom.uniform(*self.move_duration)) # 3. 微小随机延迟后点击 time.sleep(random.uniform(0.02, 0.08)) click(buttonbutton) # 4. 操作后延迟 time.sleep(random.uniform(*self.operation_delay)) def press_key(self, key, times1): for _ in range(times): press(key) time.sleep(random.uniform(0.05, 0.1))重要注意事项绝对坐标与相对坐标pyautogui和pydirectinput默认使用屏幕绝对坐标。你必须确保游戏窗口位于预设的位置或者编写代码动态获取游戏窗口的位置和大小。pydirectinputvspyautogui某些游戏特别是通过DirectInput处理输入的游戏对pyautogui的模拟输入无响应。pydirectinput尝试直接调用Windows的DirectInput API兼容性更好。实践中我通常混合使用键盘操作用pydirectinput鼠标移动用pyautogui的平滑移动功能。延迟是朋友在快速循环中如果不加入延迟AI会以非人类的速度疯狂操作不仅可能导致游戏卡顿也容易被服务器端检测。所有点击、按键之间必须插入随机延迟。4.3 决策逻辑模块构建你的AI大脑这是最具创造性的部分。一个最简单的“黑暗时代”AI流程可能如下class BasicAIBrain: def __init__(self, vision, action): self.vision vision self.action action self.state START self.villager_count 0 def run_cycle(self): if self.state START: self.initial_scout() elif self.state COLLECT_FOOD: self.manage_food_collection() elif self.state BUILD_HOUSES: self.manage_housing() # ... 更多状态 def initial_scout(self): # 1. 找到并选择起始的3个村民 villager_positions self.vision.find_on_screen(icon_villager) if villager_positions: self.action.human_click(villager_positions[0][0], villager_positions[0][1]) self.action.press_key(ctrl) # 模拟Ctrl点击进行多选需要额外逻辑 # ... 选择所有村民 self.state COLLECT_FOOD def manage_food_collection(self): # 1. 检查是否有空闲村民 # 2. 找到绵羊或浆果丛 # 3. 指挥村民前往采集 # 4. 更新食物数量判断是否升级时代或建造新建筑 food_icon_pos self.vision.find_on_screen(icon_food) if food_icon_pos: # 假设食物数量显示在图标右侧固定偏移处 # 这里需要更复杂的OCR光学字符识别来读取数字例如使用pytesseract pass决策层设计模式有限状态机FSM如上例适合编写流程明确的策略如标准开局流程黑暗-封建-城堡。行为树Behavior Tree更适合复杂的、带有条件判断和优先级的行为例如“如果受到攻击则中断采集进行防御否则继续经济发展”。与机器学习结合你可以用视觉模块获取游戏状态作为观测值用动作模块执行动作然后使用像Stable-Baselines3这样的库来训练一个强化学习智能体。Agent of Empires 框架此时就成为了一个完美的环境接口。5. 实战构建一个自动采集资源的AI让我们串联以上所有模块实现一个最简单的功能自动将空闲村民派去采集最近的浆果丛。5.1 步骤分解状态获取循环检测屏幕。识别空闲村民匹配“空闲村民”图标一个闪烁的村民头像。更可靠的方法是检测村民单位是否带有“空闲”状态光晕一个特定的颜色圈这需要颜色检测。识别浆果丛匹配浆果丛的模板。由于浆果丛在游戏中视角不同形状会变可能需要多个角度的模板或使用特征匹配如SIFT而非严格的模板匹配。路径计算与执行点击选择空闲村民 - 右键点击浆果丛。这里有一个隐含的复杂问题如何找到“最近”的浆果丛你需要结合小地图信息或通过多次屏幕搜索来估算位置。一个简化版是直接点击屏幕上识别到的第一个浆果丛。5.2 代码示例片段def auto_send_idle_to_berries(self): # 查找空闲村民图标假设已制作模板 idle_villager_icons self.vision.find_on_screen(icon_idle_villager, threshold0.7) if not idle_villager_icons: return # 查找浆果丛 berry_bush_positions self.vision.find_on_screen(berry_bush, threshold0.75) if not berry_bush_positions: print(未找到浆果丛) return # 选择第一个空闲村民图标这通常会选中所有空闲村民 self.action.human_click(idle_villager_icons[0][0], idle_villager_icons[0][1]) # 右键点击第一个浆果丛 self.action.human_click(berry_bush_positions[0][0], berry_bush_positions[0][1], buttonright) print(f已派遣空闲村民至浆果丛)5.3 调试与优化运行上述脚本你可能会遇到问题问题1点击了空闲村民图标但村民没有被选中。排查检查游戏是否处于前台且窗口模式正确。检查坐标是否正确可能是多显示器导致的偏移。使用pyautogui.displayMousePosition()工具实时查看鼠标坐标进行比对。问题2浆果丛匹配不到或匹配到错误的东西。排查降低threshold看是否能匹配到。检查模板图片是否纯净是否包含了背景。尝试在不同的游戏时间白天/黄昏和地图绿色阿拉伯、干旱阿拉伯下测试模板的鲁棒性。可能需要为不同地形准备不同的模板。问题3操作太快游戏反应不过来。解决增加ActionAgent中的各类延迟参数。在关键操作如选择大部队、发起攻击前后加入更长的等待时间time.sleep(0.5)。6. 高级话题与挑战应对6.1 动态环境与自适应识别游戏画面是动态的昼夜交替、单位重叠、建筑建造动画、屏幕滚动都会干扰静态模板匹配。应对策略包括多模板与投票机制为同一个物体如“城镇中心”准备建造中、建造完成、不同方向等多个模板。匹配时取置信度最高的结果。区域限定与状态机记忆一旦建造了一个建筑就记住其大致屏幕区域。下次寻找时优先在该区域附近搜索而不是全屏搜索。颜色分割辅助对于生命值条、资源容器矿脉、树林的存量可以通过识别特定颜色区域的比例来判断状态。6.2 战略决策与多线程一个完整的AI需要同时处理多个任务经济、军事、科技。这需要引入多线程或异步编程。主循环线程负责高频的状态感知如每0.5秒检查一次战斗单位状态。经济管理线程以较低频率如每2秒检查资源分配、村民生产、建筑建造队列。军事调度线程当发现敌人或达到特定军事规模时激活负责编队、进攻、撤退。线程间通信使用线程安全的队列queue.Queue来传递信息例如经济线程告诉军事线程“食物充足可以训练更多骑兵”。6.3 性能瓶颈与优化当模板数量增多、搜索区域变大时视觉匹配会成为性能瓶颈。分层搜索先在小地图低分辨率上定位感兴趣的区域再在全屏对应的高分辨率区域进行精细匹配。背景减除与差分法对于需要检测“变化”的场景如新出现的敌方单位可以比较连续两帧的截图差异只在发生变化区域进行匹配。使用C扩展将核心的图像匹配循环用C重写并通过Python的ctypes调用可以带来数量级的性能提升。7. 常见问题排查与经验实录以下是我在开发过程中遇到的一些典型问题及解决方案这些在标准文档里很少提及问题1模板在开发机上工作完美换台电脑或显示器后全部失效。原因与解决根本原因是屏幕缩放Display Scaling。如果Windows设置了125%或150%的缩放pyautogui.screenshot()截取的是物理像素但pyautogui.click()操作的却是缩放后的逻辑坐标两者不匹配。解决方案确保开发机和运行机使用相同的缩放比例最好都是100%或者在代码中主动获取并补偿缩放因子。可以通过ctypes.windll.shcore.GetScaleFactorForDevice(0)获取缩放比例并进行坐标换算。问题2游戏在后台时AI操作无效。原因某些游戏特别是全屏模式下的游戏会忽略发送到后台窗口的输入消息。解决确保运行AI脚本时游戏窗口始终处于活动前台。可以使用pygetwindow库来确保游戏窗口被激活。但注意频繁切换前台窗口可能引起用户反感在无头headless自动化测试中更需妥善处理。问题3匹配速度太慢导致AI反应迟钝。优化缩小搜索区域不要总是全屏匹配。如果你要找的资源图标永远在屏幕顶部就把截图区域限定在(0,0,1920,200)。降低截图分辨率对于不需要精确坐标的检测如判断是否存在某个图标可以将截图缩放至原图的50%再进行匹配速度能提升近4倍。缓存静态元素游戏界面中很多元素如菜单栏按钮位置是固定的匹配一次后记住坐标下次直接使用无需重复匹配。问题4在激烈的战斗中AI因画面特效爆炸、技能光效导致误判。策略这是视觉方法的固有难点。可以尝试使用对亮度变化不敏感的匹配方法如TM_CCOEFF_NORMED。在战斗状态下提高关键模板如“撤退”按钮的匹配阈值。引入“置信度持续验证”机制如果一个单位被识别为“骑兵”但连续几帧其匹配得分都低于阈值则将其标记为“丢失目标”而不是立即执行攻击指令。问题5如何让AI应对随机地图思路放弃对具体地形的硬编码。转而依赖更通用的策略开局后立即指挥侦察单位如侦察骑兵进行“螺旋式”探索同时用视觉模块识别探索到的资源类型树木、矿脉、浆果丛的模板是通用的并动态记录它们的位置坐标构建一个内部的简易地图。后续的决策都基于这个动态构建的内部地图。开发基于Agent of Empires的AI是一个在“自动化”和“拟人化”、“精确”与“鲁棒”之间不断寻找平衡的过程。它没有一劳永逸的解决方案每一个稳定的AI行为背后都是对游戏机制的理解、对图像识别参数的反复调试以及对异常情况的细致处理。这个过程虽然充满挑战但当你看到自己编写的代码成功地指挥千军万马完成一场复杂的攻防战时所带来的成就感是无可比拟的。这个框架提供了一个绝佳的起点而真正的智能来自于开发者无穷的创意和对细节的执着打磨。

更多文章