教程
游戏脚本制作教程:用 MAS 给任何安卓游戏做脚本
在 Macro Automation Studio 中给任何安卓游戏制作脚本的游戏脚本制作教程:从 Marketplace 安装、让 MAS Agent 编写,或在 BlueStacks 上用 Python 自己写。
- Windows
- Mac
- 模拟器
- 云手机
- 手机
- Studio
- Python SDK
本页目录
这篇游戏脚本制作教程介绍如何在 Macro Automation Studio(MAS)中给任何安卓游戏做脚本,从一个已安装的游戏,到一个按计划、在一个或多个账号上运行的脚本。MAS 脚本从屏幕出发工作:用图像找按钮,用 OCR 读计数器,用拟人化的节奏点击。适合在 Windows 或 Mac 上第一次做脚本的人。
开始之前
- 已安装 MAS 并用免费试用或套餐登录。参见安装 MAS。
- 游戏运行在 MAS 能驱动的设备上:这台电脑上的模拟器、一台云设备,或你自己的手机。参见设备。
- 设备已在某个设备组中,卡片显示已停止而不是错误。快速开始页演示了如何添加。
- 走 Python 路线不需要其他任何东西。MAS 自带 Python 环境和
mas包。
安卓游戏脚本怎么做:三种方式
从 Marketplace 安装
已经有人为你的游戏做好了脚本时,这是最快的路线。
- 打开 Marketplace,搜索游戏。
- 打开条目,点击下载。脚本会出现在宏页面。
- 在设备组中打开你的组,在设备的宏选择器里选中这个脚本,点击启动。
带截图的完整流程见如何运行 Marketplace 中的宏。现成脚本有 Whiteout Survival、Kingshot 和 Last Asylum: Plague。
让 MAS Agent 编写
没有现成条目的游戏,可以走这条无代码路线。
- 打开 Agent,选择设备。
- 用一句话描述流程,包括什么时候该停,然后点击编写。
- Agent 提问时回答它。它会停下来问,而不是猜。
- 宏通过 3 次验证运行后,点击添加到我的宏。
编写过程消耗 AI 积分;运行完成的宏不消耗任何积分。结果是一个可以打开和编辑的普通 Python 项目。参见 MAS Agent。
用 Python 自己写
完全掌控脚本做的每一个决定。本页剩下的内容就是这条路线。
用 Python 自动化安卓游戏
1. 列出脚本必须看到的东西
手动玩一遍流程,记下它经过的每个屏幕。也就是你按的按钮、打断你的弹窗、显示体力的计数器,以及表示完成的提示。每一项都会变成一张模板图片或一个 OCR 区域。知道自己停止状态的脚本,永远不会盲跑。
2. 创建项目
- 打开宏,点击新建项目。
- 选择代码型,把目标设备设为移动端,给项目命名,点击创建项目。
- 打开项目。Code Editor 会显示
src/app.py,也就是 MAS 运行的文件。
3. 在 Asset Lab 中截取模板
- 在设备上启动游戏,进入有那个按钮的屏幕。
- 在 Code Editor 中打开资源面板,点击打开资源助手。Asset Lab 会带着实时画面打开。
- 紧贴按钮裁一个矩形并保存。它会带着一个数字 ID 进入你的图片库。
- 对弹窗的关闭按钮、确认按钮和”体力不足”提示重复这一步。
- 回到资源面板,对每张图片使用复制 ID,把 ID 粘贴到脚本顶部的
mas.images中。
裁剪要小而有辨识度。整屏截图只能匹配那一个屏幕;一个按钮在任何出现的地方都能匹配。模板可以是 jpg、png、gif 或 webp,单张最大 10 MB。Asset Lab 页详细介绍这个工具。
4. 截取 OCR 区域
- 在 Asset Lab 中,围绕你要读的计数器画一个框。
- 运行实时 OCR 测试,收紧框,直到数字能干净地读出来。
- 把坐标复制到脚本里的
Region(x1, y1, x2, y2)。
如果文字读得不好,OCR 指南解释了分割模式和颜色转换。
5. 写循环
下面的循环是每个游戏脚本共有的形状。每一行都对应一个 SDK 调用:
find_object_retry最多找total_tries=3次,每次间隔time_sleep=2.0秒,没有匹配时返回None。click(x, y, delay_ms=1000)点击匹配的中心,然后等一秒让游戏响应。read_text(region, psm=7)把计数器当作单行读取。time.sleep(random.uniform(0.8, 2.0))在轮次之间加入像人一样的停顿。mas.save和mas.retrieve保存轮次计数,所以中断的运行会从上次的位置继续。- 停止条件结束循环。示例用了五个:最大轮次、时间预算、“体力不足”模板、计数器过低,以及连续找不到太多次。
6. 运行并阅读日志
在 Code Editor 中选择设备,点击运行(F5)。每条 mas.log 都会出现在运行控制台。停止是 Shift+F5。一次只改一处:模板找不到时,先重新裁剪,再碰逻辑。
7. 设置定时
- 打开定时任务,点击新建计划。
- 填写名称,选择宏和模拟器端口,设置日期和时间。
- 把重复设为每天,点击创建计划。
应用必须保持打开;定时任务在应用内部运行。参见定时任务和循环与定时。
8. 在设备组上运行
把每个账号的模拟器实例作为设备添加到同一个组,给每台设备分配脚本,点击全部启动。账号名这类按设备不同的值来自设置方案。参见多开挂机。
一个完整的示例脚本
把图片 ID 和区域替换成你截取的。这个脚本刷资源,直到体力过低、时间预算用完或完成三十轮为止,并且能在重启后继续。
import random
import sys
import time
import mas
from mas import Region
images = mas.images({
"attack_button": 101,
"confirm_button": 102,
"close_popup": 103,
"out_of_energy": 104,
})
ENERGY_REGION = Region(x1=380, y1=20, x2=520, y2=60)
TASK = "farm_bot"
MAX_ROUNDS = 30
TIME_BUDGET_S = 20 * 60
MIN_ENERGY = 10
def pause(low=0.8, high=2.0):
time.sleep(random.uniform(low, high))
def read_energy():
result = mas.read_text(region=ENERGY_REGION, psm=7)
digits = "".join(ch for ch in result.text if ch.isdigit())
return int(digits) if digits else None
def clear_popups():
popup = mas.find_any_object([images.close_popup, images.confirm_button])
if popup:
mas.click(popup.x, popup.y, delay_ms=800)
return True
return False
def main():
rounds = mas.retrieve(TASK).get("rounds", 0)
misses = 0
started = time.monotonic()
mas.log(f"Starting at round {rounds}")
while rounds < MAX_ROUNDS:
if time.monotonic() - started > TIME_BUDGET_S:
mas.log("Time budget reached", level="warning")
break
if clear_popups():
continue
if mas.find_object(images.out_of_energy):
mas.log("Out of energy, stopping")
break
energy = read_energy()
if energy is not None and energy < MIN_ENERGY:
mas.log(f"Energy {energy} is below {MIN_ENERGY}, stopping")
break
button = mas.find_object_retry(images.attack_button, total_tries=3, time_sleep=2.0)
if button is None:
misses += 1
mas.log(f"Attack button not found ({misses})", level="warning")
if misses >= 5:
mas.log("Giving up after 5 misses", level="error")
sys.exit(2)
continue
misses = 0
mas.click(button.x, button.y, delay_ms=1000)
pause()
rounds += 1
mas.save(TASK, {"rounds": rounds})
mas.log(f"Round {rounds} of {MAX_ROUNDS}")
if rounds >= MAX_ROUNDS:
mas.clear(TASK)
mas.log(f"Finished with {rounds} rounds")
if __name__ == "__main__":
main()sys.exit(2) 把这次运行标记为失败,所以订阅了 macro.failed 的 Webhook 会收到通知。正常退出报告 macro.completed。参见 Webhook。
让脚本保持稳定的技巧
- 分辨率。 模板和区域属于你截取时的分辨率和 DPI。让运行脚本的每台设备都保持同样的设置;模拟器指南以竖屏 540x960、240 DPI 为基准。
- 模板卫生。 只裁按钮,绝不带周围的背景。游戏更新改了美术后重新裁剪。一个按钮有两种样子时,两种都截下来,用
find_any_object搜索。 - 停止条件。 每个循环至少需要两个:一个计数器或时间预算,加一个表示”完成”的屏幕状态。没有它们的脚本会一直跑到你注意到为止。
- 慢一点。 轮次之间停一到两秒代价很小,看起来也没那么机械。
- 记录决定,而不是点击。
mas.log("Energy 8, stopping")告诉你运行为什么结束;一百次点击的日志做不到。
可能出什么问题
按钮永远找不到
裁剪太大、阈值对这种美术太严格,或者设备运行的分辨率和你截取时不同。裁得更紧,然后在调用上试试 threshold=0.7。图像识别指南有完整的检查清单。
计数器读出错误的数字
区域包含了旁边的图标,或者文字是深色背景上的浅色。在 Asset Lab 中收紧框,并传入 color_conversion=ColorConversion.BLACK_WHITE。OCR 指南展示了如何检查置信度。
第二天脚本一启动就停
存储的计数器已经到了上限。示例在达到 MAX_ROUNDS 时清除存储;如果你改了这一点,从一个临时脚本调用一次 mas.clear("farm_bot")。
点击落在按钮旁边
截取之后模拟器的分辨率或 DPI 变了,或者窗口不是竖屏。把模拟器显示重置为截取时的设置,重新截取仍然点不准的部分。
没有任何自动化工具是 100% 无风险的,请负责任地使用自动化,并自行斟酌决定。
下一步
相关页面
谢谢。如果有哪里不对,请在 Discord 告诉我们。
有疑问? 在 Discord 提问
