从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮
- [从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮](#从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮)
-
- 一、前言
- 二、整体架构与技术栈
- [三、ADB 控制层:截图、点击、滑动](#三、ADB 控制层:截图、点击、滑动)
- 四、核心难点一:怎么判断"真进游戏了"?
- 五、核心难点二:识别"这把刷在哪个出生点"
-
- [5.1 用圆检测把小地图"圆形抠出来"](#5.1 用圆检测把小地图"圆形抠出来")
- [5.2 模板匹配识别出生点](#5.2 模板匹配识别出生点)
- 六、核心难点三:自动拾取物资
- 七、把它串起来:固定路线
- 八、一个诚实的工程结论
- 九、总结
- 源码链接:
从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮
声明 :本文仅用于分享 Android 自动化与计算机视觉的工程实践,所有内容面向技术学习。竞技游戏的用户协议通常禁止第三方自动化工具,请勿用于线上对局。Demo 与思路仅供研究,后果自负。
先看看效果:
三角洲
https://www.bilibili.com/video/BV1AP7X6AEfh/?spm_id_from=333.1387.homepage.video_card.click
一、前言
很多人见过 B 站、CSDN 上的"自动跑刀"脚本------进图后自动跑到几个固定点位搜刮物资。这类脚本到底怎么实现?本文以《三角洲行动》手游为例,完整复盘一套**「电脑 ADB 直控真机 + OpenCV 视觉识别 + 固定路线」**的实现方案,重点讲清楚四个工程难点:
- 怎么控制手机(截图 / 点击 / 滑动)
- 怎么判断"真进游戏了"(霍夫圆检测小地图)
- 怎么识别"这把刷在哪个出生点"(小地图模板匹配)
- 怎么自动拾取物资(物资标签检测)
以及一个绕不开的结论:为什么"固定点位"方案可行,而"自主智能跑图"不可行。
二、整体架构与技术栈
PC (Python)
├─ ADB 控制层 ------ 截图 / input tap / input swipe
├─ 视觉识别层(OpenCV)
│ ├─ 霍夫圆检测 ------ 检测小地图 → 判定是否进图
│ ├─ 模板匹配 ------ 小地图比对 → 识别出生点
│ └─ 区域裁剪/遮罩 ------ 物资标签、按钮定位
└─ 决策/路线层 ------ 每个出生点一条固定动作序列
↓ ADB
Android 真机 / 模拟器
技术栈:
| 模块 | 技术 |
|---|---|
| 设备控制 | ADB(platform-tools)input tap/swipe、exec-out screencap |
| 图像处理 | OpenCV-Python(HoughCircles、matchTemplate、掩膜) |
| 数值计算 | NumPy |
| 语言 | Python 3.10 |
关键前提 :MIUI / HyperOS 等系统默认禁用 ADB 模拟点击(
INJECT_EVENTS权限),需在开发者选项中开启**「USB 调试(安全设置)」**(需插 SIM 卡 + 登录账号)。开启后adb shell input tap/swipe才可用,这是整套方案的基础。
三、ADB 控制层:截图、点击、滑动
一切的基础是「能截屏、能操作」。用 subprocess 包一层 ADB:
python
import subprocess, time
import numpy as np
import cv2
ADB = r"D:\platform-tools\adb.exe"
SERIAL = "你的设备序列号" # adb devices 查看
def adb(*args, binary=False, timeout=20):
cmd = [ADB, "-s", SERIAL] + list(args)
r = subprocess.run(cmd, capture_output=True, timeout=timeout)
return r.stdout if binary else r.stdout.decode("utf-8", "ignore")
def screenshot():
"""exec-out screencap 直接拿二进制 PNG,OpenCV 解码,无需落盘。"""
raw = adb("exec-out", "screencap", "-p", binary=True)
return cv2.imdecode(np.frombuffer(raw, np.uint8), cv2.IMREAD_COLOR)
def tap(x, y, wait=1.2):
adb("shell", "input", "tap", str(x), str(y))
time.sleep(wait)
def swipe(x1, y1, x2, y2, dur_ms=300):
adb("shell", "input", "swipe", str(x1), str(y1), str(x2), str(y2), str(dur_ms))
对局内的"走位"和"转视角",本质也是 swipe:
- 走位 = 在左手虚拟摇杆上按住拖动一段时间(
swipe的 duration 就是按住时长)。注意摇杆死区大,必须大幅度推满才会走:
python
def move_forward(seconds):
# 摇杆中心(430,760),向上推满 → 前进
swipe(430, 780, 430, 350, int(seconds * 1000))
def look_right_90():
# 右侧视角区横向滑动,约 480px ≈ 转 90°
swipe(1700, 500, 2180, 500, 350)
横屏分辨率 2400×1080 下,这些坐标都是实测标定出来的。
四、核心难点一:怎么判断"真进游戏了"?
这是最坑的一步。游戏从「点击出发」到「真正进图」要经历:匹配 → 选干员 → 着陆确认 → 加载(约30s)→ 进图 。早期我用"固定等 30 秒"或"识别匹配界面文字",都不稳------匹配时间不固定,加载界面文字时有时无,经常还没进游戏就开始乱跑刀。
突破口:对局内左上角有个圆形小地图,而菜单/加载界面没有。 于是用霍夫圆检测(HoughCircles) :检测到小地图圆 = 真进游戏。

python
def detect_minimap_circle(screen=None):
"""检测左上角小地图圆,返回 (cx,cy,r) 或 None。"""
if screen is None:
screen = screenshot()
roi = screen[0:460, 0:500] # 只在左上角找,提速
g = cv2.medianBlur(cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY), 5)
cs = cv2.HoughCircles(g, cv2.HOUGH_GRADIENT, dp=1, minDist=300,
param1=100, param2=40, minRadius=140, maxRadius=215)
if cs is None:
return None
c = cs[0][0]
return (int(c[0]), int(c[1]), int(c[2]))
def is_in_game(screen=None):
return detect_minimap_circle(screen) is not None
实测圆心稳定在 (~277, 210)、半径 ~145,几乎每把一致。is_in_game() 就是可靠的"进图判定",彻底解决了时序错位问题。
五、核心难点二:识别"这把刷在哪个出生点"
关键前提 :很多人以为出生点随机,其实不少撤离类地图的出生点就那固定的几个 。这意味着------只要识别出本把刷在哪个出生点,就能跑预先调好的对应路线。这正是"固定点位脚本"成立的根基。
识别靠小地图 :它是北朝上 + 玩家居中 的,所以同一个出生点,周围地形布局每次都一样,非常适合模板匹配。
5.1 用圆检测把小地图"圆形抠出来"
直接方形裁剪会带进会变化的世界背景(四个角),干扰匹配。更好的做法是:圆检测定位 → 圆形掩膜把圆外涂黑 → 归一化尺寸:
python
def get_minimap(screen=None):
"""抠出圆形小地图(圆外涂黑),归一化 360x360。"""
if screen is None:
screen = screenshot()
circ = detect_minimap_circle(screen)
if circ is None:
return None
cx, cy, r = circ
r = min(r + 8, cx, cy)
crop = screen[cy - r:cy + r, cx - r:cx + r].copy()
mask = np.zeros(crop.shape[:2], np.uint8)
cv2.circle(mask, (crop.shape[1] // 2, crop.shape[0] // 2), r, 255, -1)
crop = cv2.bitwise_and(crop, crop, mask=mask) # 圆外涂黑
return cv2.resize(crop, (360, 360))
配图:圆检测 + 掩膜后抠出的干净圆形小地图。


有些出生点小地图上直接带地名(如"军营""帐篷区"),还能用 OCR 读字辅助判断:
5.2 模板匹配识别出生点
提前在每个出生点出生瞬间 采集一张圆形小地图存为模板(spawn1.png、spawn2.png...),进图后拿当前小地图逐一比对,取最高分:
python
import os
def detect_spawn(screen=None, threshold=0.6):
mm = get_minimap(screen)
if mm is None:
return None
best = None
for f in os.listdir("templates/spawns"):
tpl = cv2.imread(os.path.join("templates/spawns", f))
if tpl is None or tpl.shape != mm.shape:
continue
res = cv2.matchTemplate(mm, tpl, cv2.TM_CCOEFF_NORMED)
_, maxv, _, _ = cv2.minMaxLoc(res)
if best is None or maxv > best[1]:
best = (os.path.splitext(f)[0], float(maxv))
return best if best and best[1] >= threshold else None
采集规范(踩坑经验) :模板必须统一风格 才匹配得准------① 都在出生瞬间、未移动时采集(玩家居中、初始朝向);② 统一用"圆检测 + 掩膜 + resize 360×360";③ 小地图上的玩家箭头、队友标记、区域线是动态噪声,进阶可把中心圆区再挖掉,只比静态地形。
六、核心难点三:自动拾取物资
走到物资点后,画面右上方会弹出物资标签 (如"9V电池")。坑点:拾取不是点屏幕固定的"交互键",而是点这个标签本身。
python
PICKUP_LABEL = (1600, 280) # 右上角物资标签位置(横屏)
def pickup():
tap(*PICKUP_LABEL, wait=0.6)
点中后画面提示"已拾取 XX 到保险箱",即成功。
进阶可用模板匹配/颜色检测先判断"标签框是否存在",存在再点,避免空点。
七、把它串起来:固定路线
每个出生点配一条固定动作序列,识别到哪个出生点就跑哪条:
python
ROUTES = {
# 降落点:出生 → 前进2秒 → 右转90° → 点标签拾取
"spawn2": [("forward", 2), ("look", 480, 0), ("pickup",)],
# 其它出生点继续补......
}
def run_route(name):
for step in ROUTES.get(name, []):
if step[0] == "forward":
move_forward(step[1])
elif step[0] == "look":
swipe(1700, 500, 1700 + step[1], 500, 350)
elif step[0] == "pickup":
pickup()
主循环:
python
def main_loop():
deploy() # 自动点出发/指挥出战进局
if not wait_in_game(timeout=60):# 圆检测等进图
return
spawn = detect_spawn() # 识别出生点
if spawn:
run_route(spawn[0]) # 跑对应固定路线
extract() # 撤离/自杀
back_to_lobby() # 退出结算 → 回大厅
八、一个诚实的工程结论
做下来最大的体会:"识别"不难,"导航"才难。
- 能做到:CV 识别进图、识别出生点、识别物资标签;固定出生点 + 固定路线 + 自动进局/撤离/循环。
- 做不到(靠脚本盲操作) :像人一样"自主跑图、避开墙和障碍、找到好货"。3D 场景里盲走 ADB 反复撞墙撞围栏,这需要深度感知 + 路径规划(等于游戏 AI 自主导航),是另一个数量级的工程;而真正的"自动打人"= 目标检测自瞄 = 顶格外挂,必被反作弊封号。
所以"固定点位"方案之所以流行,正是因为它用确定性(固定出生点+固定路线)绕开了最难的自主导航------这是工程上的务实取舍。
九、总结
| 难点 | 解法 |
|---|---|
| 控制手机 | ADB input tap/swipe + screencap |
| 进图判定 | 霍夫圆检测小地图 is_in_game() |
| 出生点识别 | 圆形小地图掩膜 + matchTemplate |
| 物资拾取 | 点右上角物资标签 |
| 智能跑图 | ❌ 用"固定出生点+固定路线"务实绕开 |
整套方案把 Android 自动化 和 OpenCV 模板匹配 / 霍夫圆检测 结合起来,是一个很好的"CV + 自动化"工程练习。
再次提醒:仅供学习计算机视觉与自动化技术,切勿用于线上竞技对局
源码链接:
如果这篇对你有帮助,欢迎点赞收藏。技术交流,理性使用。