从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮)三角洲自动跑刀教程

作者:深度学习教程,日期:2026/6/6

从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮

  • 从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮
    • 一、前言
    • 二、整体架构与技术栈
    • 三、ADB 控制层:截图、点击、滑动
    • 四、核心难点一:怎么判断"真进游戏了"?
    • 五、核心难点二:识别"这把刷在哪个出生点"
      • 5.1 用圆检测把小地图"圆形抠出来"
        • 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 视觉识别 + 固定路线」**的实现方案,重点讲清楚四个工程难点:

  1. 怎么控制手机(截图 / 点击 / 滑动)
  2. 怎么判断"真进游戏了"(霍夫圆检测小地图)
  3. 怎么识别"这把刷在哪个出生点"(小地图模板匹配)
  4. 怎么自动拾取物资(物资标签检测)

以及一个绕不开的结论:为什么"固定点位"方案可行,而"自主智能跑图"不可行。


二、整体架构与技术栈

1PC (Python)
2 ├─ ADB 控制层      —— 截图 / input tap / input swipe
3 ├─ 视觉识别层(OpenCV)
4     ├─ 霍夫圆检测   —— 检测小地图  判定是否进图
5     ├─ 模板匹配     —— 小地图比对  识别出生点
6     └─ 区域裁剪/遮罩 —— 物资标签、按钮定位
7 └─ 决策/路线层      —— 每个出生点一条固定动作序列
8         ADB
9   Android 真机 / 模拟器
10

技术栈

模块技术
设备控制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:

1import subprocess, time
2import numpy as np
3import cv2
4
5ADB = r"D:\platform-tools\adb.exe"
6SERIAL = "你的设备序列号"   # adb devices 查看
7
8def adb(*args, binary=False, timeout=20):
9    cmd = [ADB, "-s", SERIAL] + list(args)
10    r = subprocess.run(cmd, capture_output=True, timeout=timeout)
11    return r.stdout if binary else r.stdout.decode("utf-8", "ignore")
12
13def screenshot():
14    """exec-out screencap 直接拿二进制 PNG,OpenCV 解码,无需落盘。"""
15    raw = adb("exec-out", "screencap", "-p", binary=True)
16    return cv2.imdecode(np.frombuffer(raw, np.uint8), cv2.IMREAD_COLOR)
17
18def tap(x, y, wait=1.2):
19    adb("shell", "input", "tap", str(x), str(y))
20    time.sleep(wait)
21
22def swipe(x1, y1, x2, y2, dur_ms=300):
23    adb("shell", "input", "swipe", str(x1), str(y1), str(x2), str(y2), str(dur_ms))
24

对局内的"走位"和"转视角",本质也是 swipe:

  • 走位 = 在左手虚拟摇杆上按住拖动一段时间(swipe 的 duration 就是按住时长)。注意摇杆死区大,必须大幅度推满才会走:
1def move_forward(seconds):
2    # 摇杆中心(430,760),向上推满  前进
3    swipe(430, 780, 430, 350, int(seconds * 1000))
4
5def look_right_90():
6    # 右侧视角区横向滑动,约 480px   90°
7    swipe(1700, 500, 2180, 500, 350)
8

横屏分辨率 2400×1080 下,这些坐标都是实测标定出来的。


四、核心难点一:怎么判断"真进游戏了"?

这是最坑的一步。游戏从「点击出发」到「真正进图」要经历:匹配 → 选干员 → 着陆确认 → 加载(约30s)→ 进图。早期我用"固定等 30 秒"或"识别匹配界面文字",都不稳——匹配时间不固定,加载界面文字时有时无,经常还没进游戏就开始乱跑刀

突破口:对局内左上角有个圆形小地图,而菜单/加载界面没有。 于是用霍夫圆检测(HoughCircles):检测到小地图圆 = 真进游戏。

1def detect_minimap_circle(screen=None):
2    """检测左上角小地图圆,返回 (cx,cy,r)  None。"""
3    if screen is None:
4        screen = screenshot()
5    roi = screen[0:460, 0:500]                       # 只在左上角找,提速
6    g = cv2.medianBlur(cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY), 5)
7    cs = cv2.HoughCircles(g, cv2.HOUGH_GRADIENT, dp=1, minDist=300,
8                          param1=100, param2=40, minRadius=140, maxRadius=215)
9    if cs is None:
10        return None
11    c = cs[0][0]
12    return (int(c[0]), int(c[1]), int(c[2]))
13
14def is_in_game(screen=None):
15    return detect_minimap_circle(screen) is not None
16

实测圆心稳定在 (~277, 210)、半径 ~145,几乎每把一致。is_in_game() 就是可靠的"进图判定",彻底解决了时序错位问题。


五、核心难点二:识别"这把刷在哪个出生点"

关键前提:很多人以为出生点随机,其实不少撤离类地图的出生点就那固定的几个。这意味着——只要识别出本把刷在哪个出生点,就能跑预先调好的对应路线。这正是"固定点位脚本"成立的根基。

识别靠小地图:它是北朝上 + 玩家居中的,所以同一个出生点,周围地形布局每次都一样,非常适合模板匹配

5.1 用圆检测把小地图"圆形抠出来"

直接方形裁剪会带进会变化的世界背景(四个角),干扰匹配。更好的做法是:圆检测定位 → 圆形掩膜把圆外涂黑 → 归一化尺寸

1def get_minimap(screen=None):
2    """抠出圆形小地图(圆外涂黑),归一化 360x360。"""
3    if screen is None:
4        screen = screenshot()
5    circ = detect_minimap_circle(screen)
6    if circ is None:
7        return None
8    cx, cy, r = circ
9    r = min(r + 8, cx, cy)
10    crop = screen[cy - r:cy + r, cx - r:cx + r].copy()
11    mask = np.zeros(crop.shape[:2], np.uint8)
12    cv2.circle(mask, (crop.shape[1] // 2, crop.shape[0] // 2), r, 255, -1)
13    crop = cv2.bitwise_and(crop, crop, mask=mask)        # 圆外涂黑
14    return cv2.resize(crop, (360, 360))
15

配图:圆检测 + 掩膜后抠出的干净圆形小地图。


有些出生点小地图上直接带地名(如"军营"“帐篷区”),还能用 OCR 读字辅助判断:

5.2 模板匹配识别出生点

提前在每个出生点出生瞬间采集一张圆形小地图存为模板(spawn1.pngspawn2.png…),进图后拿当前小地图逐一比对,取最高分:

1import os
2def detect_spawn(screen=None, threshold=0.6):
3    mm = get_minimap(screen)
4    if mm is None:
5        return None
6    best = None
7    for f in os.listdir("templates/spawns"):
8        tpl = cv2.imread(os.path.join("templates/spawns", f))
9        if tpl is None or tpl.shape != mm.shape:
10            continue
11        res = cv2.matchTemplate(mm, tpl, cv2.TM_CCOEFF_NORMED)
12        _, maxv, _, _ = cv2.minMaxLoc(res)
13        if best is None or maxv > best[1]:
14            best = (os.path.splitext(f)[0], float(maxv))
15    return best if best and best[1] >= threshold else None
16

采集规范(踩坑经验):模板必须统一风格才匹配得准——① 都在出生瞬间、未移动时采集(玩家居中、初始朝向);② 统一用"圆检测 + 掩膜 + resize 360×360";③ 小地图上的玩家箭头、队友标记、区域线是动态噪声,进阶可把中心圆区再挖掉,只比静态地形。


六、核心难点三:自动拾取物资

走到物资点后,画面右上方会弹出物资标签(如"9V电池")。坑点:拾取不是点屏幕固定的"交互键",而是点这个标签本身。

1PICKUP_LABEL = (1600, 280)   # 右上角物资标签位置(横屏)
2
3def pickup():
4    tap(*PICKUP_LABEL, wait=0.6)
5

点中后画面提示"已拾取 XX 到保险箱",即成功。

进阶可用模板匹配/颜色检测先判断"标签框是否存在",存在再点,避免空点。


七、把它串起来:固定路线

每个出生点配一条固定动作序列,识别到哪个出生点就跑哪条:

1ROUTES = {
2    # 降落点:出生  前进2秒  右转90°  点标签拾取
3    "spawn2": [("forward", 2), ("look", 480, 0), ("pickup",)],
4    # 其它出生点继续补……
5}
6
7def run_route(name):
8    for step in ROUTES.get(name, []):
9        if step[0] == "forward":
10            move_forward(step[1])
11        elif step[0] == "look":
12            swipe(1700, 500, 1700 + step[1], 500, 350)
13        elif step[0] == "pickup":
14            pickup()
15

主循环:

1def main_loop():
2    deploy()                        # 自动点出发/指挥出战进局
3    if not wait_in_game(timeout=60):# 圆检测等进图
4        return
5    spawn = detect_spawn()          # 识别出生点
6    if spawn:
7        run_route(spawn[0])         # 跑对应固定路线
8    extract()                       # 撤离/自杀
9    back_to_lobby()                 # 退出结算  回大厅
10

八、一个诚实的工程结论

做下来最大的体会:"识别"不难,"导航"才难。

  • 能做到:CV 识别进图、识别出生点、识别物资标签;固定出生点 + 固定路线 + 自动进局/撤离/循环。
  • 做不到(靠脚本盲操作):像人一样"自主跑图、避开墙和障碍、找到好货"。3D 场景里盲走 ADB 反复撞墙撞围栏,这需要深度感知 + 路径规划(等于游戏 AI 自主导航),是另一个数量级的工程;而真正的"自动打人"= 目标检测自瞄 = 顶格外挂,必被反作弊封号。

所以"固定点位"方案之所以流行,正是因为它用确定性(固定出生点+固定路线)绕开了最难的自主导航——这是工程上的务实取舍。


九、总结

难点解法
控制手机ADB input tap/swipe + screencap
进图判定霍夫圆检测小地图 is_in_game()
出生点识别圆形小地图掩膜 + matchTemplate
物资拾取点右上角物资标签
智能跑图❌ 用"固定出生点+固定路线"务实绕开

整套方案把 Android 自动化OpenCV 模板匹配 / 霍夫圆检测 结合起来,是一个很好的"CV + 自动化"工程练习。

再次提醒:仅供学习计算机视觉与自动化技术,切勿用于线上竞技对局

源码链接:


如果这篇对你有帮助,欢迎点赞收藏。技术交流,理性使用。


从零实现《三角洲行动》手游自动跑刀脚本:ADB 直控 + OpenCV 视觉识别 + 固定点位搜刮)三角洲自动跑刀教程》 是转载文章,点击查看原文


相关推荐


React Native + RNOH:跨页面数据回传的最佳实践与避坑指南
皮蛋小精灵2026/5/31

从内存闭包到官方路由通信的深度对比 技术栈: React Native 0.77 + React Navigation v7 + RNOH(React Native OpenHarmony) 适用场景: 表单录入、列表选择器、跨页面数据回传通信 一句话结论: 内存闭包 Bridge 体验虽好但存在“热重载失效、系统回收丢回调、嵌套覆盖”三大致命缺陷;官方 route.params 需配合 setParams 清洗;在嵌套/鸿蒙 JS Stack 下,使用 CommonActions.setPa


aardio从惊喜到失望到被拉黑二三事
1681692026/5/9

aardio从惊喜到失望到被拉黑二三事 前情 其实我非常喜欢开发一些小工具,用于解决工作中和生活中的问题,我个人也有开发一些小程序和一些cli,但是对于桌面端一直没的找到好的开发方案,其中有试过autohotkey,但是它的语法和学习资料非常少,带你开发GUI就更少了,平时也就用用热词热键什么的,electron我也用过,但是它太重了,一直想找一个轻量点的,我也知道c#开发桌面工具非常不错,但是那要重新学一门语言,有想过学,但是一看c#教程就犯困也就没什么尝试了,直到某一天看到了aardio,真


一觉醒来,大模型就帮我排查完页面性能问题
candyTong2026/4/29

最近遇到一个性能问题,我让大模型自己去处理,然后就去午休了,醒来之后,它还真的把问题找出来并修复了 先说结果 最终定位出来的根因是: 这个业务工作台的查询表单,把 Formily 的 form 实例塞进了带 devtools 的 Zustand store。 这件事在开发环境里会非常要命,因为 form 不是一个轻量对象,它里面带着大量字段状态、reaction、effect、schema 和联动信息。 一旦进了 store,又被 devtools 观察、快照、序列化,内存就会被瞬间放大。


打造工业级全栈文件管理器:深度解析上传、回收站与三重下载流控技术
微特尔普拉斯2026/4/20

在构建企业级 Web 应用时,文件管理器是一个看似简单实则充满挑战的模块。面对大文件上传卡顿、大文件下载导致浏览器崩溃、以及误删不可恢复等痛点,我们需要一套更科学的架构方案。 本文将通过 Vue 2/3 + Spring Boot 的组合,详细拆解如何实现一套具备:排重检测、多线程后台下载、流式下载进度监控、以及回收站机制的文件管理系统。 一、 核心技术原理分析 1. 智能冲突检测上传 在上传文件前,系统会先发起一个“预检请求”(Check Exists)。 原理:前端获取文件名


一文搞懂Harness Engineering与Meta-Harness
GreenTea2026/4/12

一、什么是Harness Engineering harness engineering目前没有官方的英文翻译,但是我认为“驾驭工程”非常合适。“驾驭”一词本身有两层含义,“释放”与“约束”这两个相辅相成的维度,打个形象的比方,跟古代君臣关系一样,既要委以重任,又要设立制衡。 我们可以将这两层含义拆解如下: 1.1 释放潜力:让 AI 像工程师一样“真刀真枪”地干活 把模型放到现场,赋予了工程现场的实权,像一个工程师一样干活,能够接触代码库、执行命令,释放模型的潜力 传统的 Copilot


大模型应用开发学习第一天
程序员雷欧2026/4/4

从今天开始,雷欧将和大家一起学习大模型应用开发。我们不搞基础,不搞虚的,只搞最重要的知识来学习。         今天,我们要学习的是Transformer架构!!当然,底层机理,包括代码实现,并不需要我们知道,那么,我们需要学会什么呢?咱接着往下看……         首先,简单介绍一下什么是Transformer,Transformer是一种基于纯注意力机制的神经网络架构,由谷歌在2017年提出,最初用于机器翻译任务,现在已成为NLP和CV领域的基础架构。 1.Transformer整


腾讯云WorkBuddy实战, 全场景智能体工作搭子,这只龙虾真能帮你干活吗
不惑_2026/3/26

全网都在养虾。 朋友圈被刷屏了。同事也在搞。连高盛的分析师都惊了,说中国人接受AI的速度令人震惊。 但说实话,在我真正装上WorkBuddy之前,我是持怀疑态度的。 之前OpenClaw火的时候,很多人的真实体验是,折腾三小时,报错二十次,连命令行都没跑起来。一个面向普通人的AI工具,如果连安装都搞不定,那跟没有有什么区别? 所以当腾讯说WorkBuddy零部署、下载就能用的时候, 我第一反应是,真的假的。 ▲ WorkBuddy桌面端主界面,打开就是一个对话框,简洁到有点不像腾讯的风格 装上


JavaScript 中 Map 的完整解析
小李子呢02112026/3/18

Map 是 ES6 新增的键值对集合类型,专门用于解决普通对象({})作为键值存储的痛点(比如键只能是字符串 / 符号、无法直接获取长度等)。 1. 核心特性 特性说明键的类型可以是任意类型(数字、字符串、布尔值、对象、函数、null/undefined)遍历顺序严格按照插入顺序遍历(普通对象不保证)长度获取直接通过 map.size 获取(普通对象需手动计算 Object.keys(obj).length)键的唯一性同一个键只能存一个值(重复设值会覆盖)内存 / 性能存储大量键值对时,Ma


动态规划 线性 DP 经典四题一遍吃透
乌萨奇也要立志学C++2026/3/10

文章目录 台阶问题最大子段和传球游戏乌龟棋 线性dp 是动态规划问题中最基础、最常⻅的⼀类问题。它的特点是状态转移只依赖于前⼀个或前⼏个状态,状态之间的关系是线性的,通常可以⽤⼀维或者⼆维数组来存储状态。 我们在⼊⻔阶段解决的《下楼梯》以及《数字三⻆形》其实都是线性dp,⼀个是⼀维的,另⼀个是⼆ 维的。 台阶问题 题目描述 题目解析 本题就是上一节下楼梯的问题的加强版,总体思路不变,下面我们还是按照动规5板斧来分析一下这道题。 1、状态表示 dp[i]表示走到


一款使用 C# 编写专为 Windows 11 打造的文件资源管理器增强工具!
追逐时光者2026/3/2

前言 在 Windows 11 中,文件资源管理器虽已支持标签页,但默认行为仍会打开多个独立窗口,容易造成桌面混乱。今天大姚给大家分享一款专为 Windows 11 打造的文件资源管理器增强工具:ExplorerTabUtility,它能够自动将新打开的资源管理器窗口转换为标签页,助您实现更简洁、更有条理的文件管理体验。 工具介绍 ExplorerTabUtility 是一款使用 C# 编写专为 Windows 11 文件资源管理器设计的增强型工具,开源免费(MIT license),旨在解决原

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读