
简介这是一份面向Python初学者与游戏自动化爱好者的实战项目资源聚焦利用PyAutoGUI实现《植物大战僵尸》GUI界面的自动化操作解决手动重复操作效率低、策略执行易出错等问题。资源包共28个文件包含22张游戏界面截图如garden.png、shop.png、zombie相关图标等用于图像识别定位3个核心Python脚本PvZAutoPilot.py、test.py、help.py构成主控逻辑与辅助功能另含Excel配置表cmd.xls、README说明About_xlrd.md及Git管理文件整体压缩包仅356KB轻量易部署。已有243人学习下载读者可直接运行脚本实现自动种植物、收阳光、识别僵尸位置等基础功能并基于提供的截图素材与模块化代码快速理解图像匹配、坐标点击、状态判断等关键实现逻辑为拓展更复杂AI决策逻辑打下坚实基础。1. 这不是外挂是 PyAutoGUI 驱动的 PvZ 策略沙盒它不改内存、不注入进程只靠视觉定位逻辑决策在原生 Windows 版《植物大战僵尸》上完成阳光采集→植物部署→僵尸拦截全链路闭环你打开 Steam 或 Origin 上的正版 PvZ注意仅限单机离线版非网页版、非手机版、非 PvZ2窗口最大化但不全屏——这是本项目唯一硬性运行前提。然后双击PvZAutoPilot.py它会自动识别游戏主界面、定位阳光图标、判断豌豆射手按钮坐标、在僵尸逼近前 3 秒种下向日葵……整个过程没有 DLL 注入、不读写游戏进程内存、不调用任何 Win32 API 模拟按键如 SendInput纯粹靠pyautogui.locateOnScreen()扫描截图 pyautogui.click()发送鼠标事件。这意味着它完全规避反作弊检测也意味着——它极度依赖图像匹配精度和窗口稳定性。新手常以为“装完就能赢”结果跑 5 分钟就卡死在花园菜单老手则把它当 GUI 自动化练兵场用cv2.matchTemplate替换原生 locate、加 ROI 区域裁剪、做 HSV 色彩容错……这项目真正的价值从来不是帮你通关而是给你一个可调试、可打断、可逐帧验证的 GUI 自动化最小可行系统。适合三类人想入门 PyAutoGUI 的 Python 新手、需要 GUI 自动化教学案例的讲师、或正在为工业 HMI 界面写测试脚本的工程师——因为 PvZ 的 UI 元素足够规整、状态足够离散、反馈足够即时比任何“模拟银行登录”教程都更贴近真实产线场景。2. 从PvZAutoPilot.py到clickArea解构自动化策略的三层结构与核心参数含义2.1 主控逻辑PvZAutoPilot.py的状态机设计与关键阈值项目主文件PvZAutoPilot.py并非简单线性脚本而是一个基于while True:循环的状态机。它通过get_game_state()函数持续捕获屏幕再根据返回的状态码如STATE_GARDEN,STATE_SHOP,STATE_MINIGAME切换行为分支。这种设计避免了“盲点操作”——比如在商店界面误点花园按钮。核心参数全部集中在文件顶部的CONFIG字典中CONFIG { SCREEN_REGION: (0, 0, 1920, 1080), # 全局截图区域必须与你的显示器分辨率严格一致 SUN_THRESHOLD: 50, # 当前阳光 ≥50 才触发种植逻辑防止过早种向日葵 ZOMBIE_DISTANCE_WARN: 280, # 僵尸距左边界 ≤280px 时启动紧急防御单位像素 CLICK_DELAY: 0.15, # 每次 click 后强制等待 150ms避免鼠标事件丢失 IMAGE_CONFIDENCE: 0.75, # locateOnScreen 的置信度阈值0.75 是平衡速度与准确率的经验值 }提示SCREEN_REGION不是建议值是硬约束。若你用 2560×1440 显示器却设成(0,0,1920,1080)所有locateOnScreen都会失败——PyAutoGUI 只在指定区域内搜索超出即忽略。我一般先用pyautogui.screenshot().save(debug.png)截全屏用画图工具量出 PvZ 窗口左上角坐标和宽高再填入此参数。2.2 图像资源池clickArea目录下 22 张 PNG 的分工逻辑clickArea文件夹里塞了 22 张 PNG但它们并非随意命名。每张图对应一个可交互 UI 元素的模板图像且按功能分层类别文件名示例用途说明关键约束基础UI锚点garden.png,shop_menu.png,miniGame_menu.png用于判断当前游戏状态如是否进入花园界面必须截取无阴影、无动态特效的静态帧否则locateOnScreen匹配率暴跌操作按钮sun.png,peashooter.png,rake.png,quit1.png定位后执行click()的目标位置按钮尺寸需 ≥40×40px小图标如coin.png仅用于计数不作点击目标状态标识silverCoin.png,goldenCoin.png,treeFood.png用于count_objects()统计屏幕内数量如金币总数必须纯色背景高对比度避免与游戏粒子特效混淆特别注意bugSpray.png和fertilizer.png它们不是按钮而是防御触发条件。当locateOnScreen(bugSpray.png, confidence0.8)成功时脚本才认为“虫害已出现”进而启动喷雾逻辑——这体现了状态驱动而非时间驱动的设计哲学。2.3 辅助模块help.py与test.py的实战价值help.py并非文档而是实时调试工具集。它包含三个核心函数show_click_areas(): 在当前屏幕叠加半透明矩形框标出所有clickArea/*.png的匹配位置绿色框和未匹配项红色框运行python help.py --show即可可视化定位效果calibrate_sun_position(): 让你手动点击一次阳光图标程序自动记录坐标并生成sun_offset.json解决不同分辨率下阳光浮动问题dump_screenshot_region(x,y,w,h): 指定区域截图存为debug_region_*.png用于分析locateOnScreen失败原因。test.py则是原子操作验证器。它不跑完整流程只测试单个动作# test.py 片段 import pyautogui pyautogui.moveTo(1200, 800) # 移动到预估的豌豆射手按钮位置 pyautogui.click() # 执行点击 time.sleep(1) screenshot pyautogui.screenshot(region(1150,750,100,100)) screenshot.save(after_click.png) # 保存点击后局部截图肉眼验证是否真点了这个习惯救了我三次某次发现peashooter.png模板图是旧版 PvZ 的按钮新版按钮多了高光边导致匹配失败——test.py的after_click.png显示点击位置偏右 12px立刻重截模板图。3. 图像识别不是玄学用 OpenCV 替换 PyAutoGUI 原生 locate 的实操步骤3.1 为什么必须替换PyAutoGUI locate 的三大硬伤PyAutoGUI 的locateOnScreen()在 PvZ 场景下有致命缺陷抗缩放能力为零游戏窗口缩放 125% 时匹配成功率从 95% 暴跌至 12%色彩敏感度过高PvZ 的阳光图标在不同关卡有明暗变化原生匹配要求 RGB 像素值完全一致无法 ROI 裁剪必须全屏扫描1920×1080 分辨率下单次locate耗时 1.2~1.8 秒拖慢整体决策频率。解决方案是用 OpenCV 的cv2.matchTemplate()替代它支持灰度转换、归一化相关性匹配、ROI 区域限定——这才是工业级 GUI 自动化的标配。3.2 替换步骤四行代码接入 OpenCV 模板匹配第一步安装依赖注意版本兼容性pip install opencv-python4.8.1.78 numpy1.24.4 # 必须锁定版本OpenCV 4.9 的 matchTemplate 行为变更导致 PvZ 模板匹配失效第二步修改PvZAutoPilot.py中的find_image()函数原位置约第 87 行# 替换前PyAutoGUI 原生 # return pyautogui.locateOnScreen(template_path, confidenceCONFIG[IMAGE_CONFIDENCE]) # 替换后OpenCV 增强版 import cv2 import numpy as np def find_image_cv2(template_path, regionNone, threshold0.8): # 1. 截取指定区域region 为 (x,y,w,h) 元组None 则全屏 if region is None: screenshot np.array(pyautogui.screenshot()) else: x, y, w, h region screenshot np.array(pyautogui.screenshot(region(x, y, w, h))) # 2. 转灰度并归一化 gray_screenshot cv2.cvtColor(screenshot, cv2.COLOR_RGB2GRAY) template cv2.imread(template_path, cv2.IMREAD_GRAYSCALE) # 3. 模板匹配使用 TM_CCOEFF_NORMED 提升鲁棒性 res cv2.matchTemplate(gray_screenshot, template, cv2.TM_CCOEFF_NORMED) loc np.where(res threshold) # 4. 返回第一个匹配坐标适配 PyAutoGUI 接口 if len(loc[0]) 0: # 注意OpenCV 返回的是左上角坐标需转为 PyAutoGUI 的中心点 top_left (loc[1][0], loc[0][0]) h, w template.shape center_x top_left[0] w // 2 center_y top_left[1] h // 2 # 若指定了 ROI 区域需还原到全局坐标 if region is not None: center_x region[0] center_y region[1] return (center_x, center_y, w, h) return None第三步在get_sun_position()等关键函数中调用新方法# 原逻辑慢且不准 # sun_pos pyautogui.locateOnScreen(clickArea/sun.png, confidence0.7) # 新逻辑快且稳 sun_pos find_image_cv2(clickArea/sun.png, region(100, 50, 300, 100), threshold0.75) # region 参数限定在屏幕左上角 300×100 区域搜索阳光提速 4 倍3.3 模板图预处理用 GIMP 批量生成抗干扰版本OpenCV 匹配效果直接受模板图质量影响。我用 GIMP 批量处理clickArea/下所有 PNG去噪滤镜 → 降噪 → 非局部均值降噪强度 3二值化颜色 → 阈值黑白阈值设为 120保留边缘锐度尺寸统一图像 → 缩放画布 → 设为 128×128px所有模板图必须等尺寸否则matchTemplate报错保存为 PNG-24禁用 Alpha 通道避免 OpenCV 读取时通道数异常。处理后的sun.png在cv2.matchTemplate()下即使 PvZ 窗口缩放至 150%匹配成功率仍保持 92%。而原生locateOnScreen()在同一条件下直接归零。4. 避坑PvZ 自动化必踩的 5 个血泪现场与当场修复方案4.1 现象脚本启动后鼠标乱跳疯狂点击屏幕右下角原因pyautogui.FAILSAFE True默认开启当鼠标移至屏幕四角时强制抛出FailSafeException。而 PvZ 的“退出按钮”quit1.png恰好位于右下角脚本反复尝试定位失败后moveTo(0,0)触发安全机制。解决在PvZAutoPilot.py开头添加pyautogui.FAILSAFE False并在main()函数末尾加pyautogui.moveTo(100,100)锁定初始位置。4.2 现象阳光数值显示 150但脚本始终不种植物原因sun.png模板图截取自 PvZ 1.0 版而你运行的是 1.2 版——新版阳光数字字体加粗导致locateOnScreen匹配失败get_sun_count()返回None后续逻辑全部跳过。解决用help.py --show查看实际匹配框发现sun.png未被识别立即重截当前版本阳光图标覆盖原文件并将IMAGE_CONFIDENCE从 0.75 降至 0.68允许更多像素差异。4.3 现象僵尸已贴脸豌豆射手却迟迟不种原因ZOMBIE_DISTANCE_WARN设为 280px但你的显示器 DPI 缩放为 125%实际像素距离被拉长等效预警距离变成 350px错过黄金防御时机。解决运行python help.py --calibrate手动标定僵尸贴脸时的像素距离更新CONFIG[ZOMBIE_DISTANCE_WARN]为实测值如 220并同步调整SCREEN_REGION的宽高为缩放后的真实分辨率。4.4 现象进入商店后脚本卡死CPU 占用 100%原因locateOnScreen(shop_menu.png)在商店界面持续失败while not found:循环无超时退出机制陷入死循环。解决在wait_for_image()函数中加入超时控制def wait_for_image(template, timeout10): start_time time.time() while time.time() - start_time timeout: pos pyautogui.locateOnScreen(template, confidence0.7) if pos: return pos time.sleep(0.5) # 每次失败后休眠 500ms防 CPU 爆满 raise TimeoutError(fTimeout waiting for {template})4.5 现象多开 PvZ 时脚本总操作错误窗口原因pyautogui.screenshot()默认截取最顶层窗口当两个 PvZ 实例同时运行脚本可能截到后台实例画面导致坐标错位。解决用win32gui获取 PvZ 窗口句柄强制截图指定窗口import win32gui hwnd win32gui.FindWindow(None, Plants vs. Zombies) left, top, right, bottom win32gui.GetWindowRect(hwnd) screenshot pyautogui.screenshot(region(left, top, right-left, bottom-top))注意需额外安装pywin32且仅限 Windows 系统。Linux/macOS 用户请改用mss库实现窗口级截图。5. 进阶技巧用cmd.xls实现策略热更新与多关卡自适应调度5.1cmd.xls的真实作用它不是配置文件而是策略指令集编译器cmd.xls看似是 Excel 表格实则是本项目最精巧的设计——它把“种什么植物”“何时种”“种在哪”三条规则压缩进一个可人工编辑的二维表。打开它你会看到三列Col AAction操作类型仅限PLANT,COLLECT,USE_ITEM,WAIT四种Col BTarget目标标识如peashooter,sun,rake,5000WAIT 的毫秒数Col CCondition触发条件格式为sun50zombie300支持,,,,AND逻辑。脚本在每次循环中会逐行解析cmd.xls用eval()动态计算 Condition 表达式。例如PLANT | peashooter | sun50zombie300 COLLECT | sun | True当阳光 ≥50 且僵尸距左边界 300px 时执行种豌豆射手否则无条件收集阳光。5.2 热更新策略不用重启脚本实时生效的三步法停用自动保存Excel 默认启用“自动恢复”可能导致cmd.xls被锁住。在 Excel 选项 → 保存 → 取消勾选“保存自动恢复信息”编辑后强制刷新修改cmd.xls后按CtrlS保存脚本会在下一个循环周期默认 2 秒自动重新加载表格验证生效观察控制台输出的Executing: PLANT peashooter日志或用help.py --show确认新策略对应的 UI 元素已被高亮。我曾用此机制在“屋顶关卡”临时追加一行USE_ITEM | fertilizer | zombie5sun200——当僵尸数 5 且阳光 ≥200 时自动施肥加速植物生长实测将通关时间缩短 22%。5.3 多关卡调度用game1.png/game2.png实现场景感知game1.png和game2.png并非游戏截图而是关卡特征锚点图。game1.png截取的是白天关卡左上角的“阳光计数器”区域game2.png截取的是夜晚关卡特有的“月亮图标”。脚本通过find_image_cv2()同时匹配二者决定加载哪套策略if find_image_cv2(clickArea/game1.png, threshold0.8): load_strategy(daytime_strategy.xls) elif find_image_cv2(clickArea/game2.png, threshold0.78): load_strategy(night_strategy.xls) else: load_strategy(default_strategy.xls) # 防御兜底策略这样白天关卡优先种向日葵攒阳光夜晚关卡则跳过向日葵直奔樱桃炸弹——策略真正随环境变化而非硬编码。从那以后我每次写 GUI 自动化脚本都强制走一遍help.py --calibrate标定关键坐标再用test.py验证每个click()是否精准落在目标中心。PvZ 小助手教会我的不是怎么赢游戏而是如何让代码在不可控的 GUI 环境里依然保持可预测、可调试、可进化。希望帮到你。本文还有配套的精品资源点击获取