当前位置: 首页 > news >正文

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

从零实现《三角洲行动》手游自动跑刀脚本: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. 怎么自动拾取物资(物资标签检测)

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


二、整体架构与技术栈

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

技术栈

模块技术
设备控制ADB(platform-tools)input tap/swipeexec-out screencap
图像处理OpenCV-Python(HoughCirclesmatchTemplate、掩膜)
数值计算NumPy
语言Python 3.10

关键前提:MIUI / HyperOS 等系统默认禁用 ADB 模拟点击(INJECT_EVENTS权限),需在开发者选项中开启**「USB 调试(安全设置)」**(需插 SIM 卡 + 登录账号)。开启后adb shell input tap/swipe才可用,这是整套方案的基础。


三、ADB 控制层:截图、点击、滑动

一切的基础是「能截屏、能操作」。用subprocess包一层 ADB:

importsubprocess,timeimportnumpyasnpimportcv2 ADB=r"D:\platform-tools\adb.exe"SERIAL="你的设备序列号"# adb devices 查看defadb(*args,binary=False,timeout=20):cmd=[ADB,"-s",SERIAL]+list(args)r=subprocess.run(cmd,capture_output=True,timeout=timeout)returnr.stdoutifbinaryelser.stdout.decode("utf-8","ignore")defscreenshot():"""exec-out screencap 直接拿二进制 PNG,OpenCV 解码,无需落盘。"""raw=adb("exec-out","screencap","-p",binary=True)returncv2.imdecode(np.frombuffer(raw,np.uint8),cv2.IMREAD_COLOR)deftap(x,y,wait=1.2):adb("shell","input","tap",str(x),str(y))time.sleep(wait)defswipe(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 就是按住时长)。注意摇杆死区大,必须大幅度推满才会走:
defmove_forward(seconds):# 摇杆中心(430,760),向上推满 → 前进swipe(430,780,430,350,int(seconds*1000))deflook_right_90():# 右侧视角区横向滑动,约 480px ≈ 转 90°swipe(1700,500,2180,500,350)

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


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

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

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

defdetect_minimap_circle(screen=None):"""检测左上角小地图圆,返回 (cx,cy,r) 或 None。"""ifscreenisNone: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)ifcsisNone:returnNonec=cs[0][0]return(int(c[0]),int(c[1]),int(c[2]))defis_in_game(screen=None):returndetect_minimap_circle(screen)isnotNone

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


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

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

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

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

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

defget_minimap(screen=None):"""抠出圆形小地图(圆外涂黑),归一化 360x360。"""ifscreenisNone:screen=screenshot()circ=detect_minimap_circle(screen)ifcircisNone:returnNonecx,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)# 圆外涂黑returncv2.resize(crop,(360,360))

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


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

5.2 模板匹配识别出生点

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

importosdefdetect_spawn(screen=None,threshold=0.6):mm=get_minimap(screen)ifmmisNone:returnNonebest=Noneforfinos.listdir("templates/spawns"):tpl=cv2.imread(os.path.join("templates/spawns",f))iftplisNoneortpl.shape!=mm.shape:continueres=cv2.matchTemplate(mm,tpl,cv2.TM_CCOEFF_NORMED)_,maxv,_,_=cv2.minMaxLoc(res)ifbestisNoneormaxv>best[1]:best=(os.path.splitext(f)[0],float(maxv))returnbestifbestandbest[1]>=thresholdelseNone

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


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

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

PICKUP_LABEL=(1600,280)# 右上角物资标签位置(横屏)defpickup():tap(*PICKUP_LABEL,wait=0.6)

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

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


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

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

ROUTES={# 降落点:出生 → 前进2秒 → 右转90° → 点标签拾取"spawn2":[("forward",2),("look",480,0),("pickup",)],# 其它出生点继续补……}defrun_route(name):forstepinROUTES.get(name,[]):ifstep[0]=="forward":move_forward(step[1])elifstep[0]=="look":swipe(1700,500,1700+step[1],500,350)elifstep[0]=="pickup":pickup()

主循环:

defmain_loop():deploy()# 自动点出发/指挥出战进局ifnotwait_in_game(timeout=60):# 圆检测等进图returnspawn=detect_spawn()# 识别出生点ifspawn:run_route(spawn[0])# 跑对应固定路线extract()# 撤离/自杀back_to_lobby()# 退出结算 → 回大厅

八、一个诚实的工程结论

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

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

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


九、总结

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

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

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

源码链接:


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

http://www.jsqmd.com/news/1266618/

相关文章:

  • 2026乌鲁木齐厨房渗水到楼下怎么办?自来水管暗管检测方法,仪器测漏收费标准 - 宅安选房屋修缮
  • 把 Claude Code 的手脚管住,权限模式才是 Agentic Coding 的安全阀
  • h2oGPT:开源大模型本地化部署与隐私保护实践
  • 电气自动化机电一体化专业最好的学校——四川仪表工业学校 - 学习招生
  • AI论文降重工具实测与学术写作优化技巧
  • TI无线MCU射频核心命令机制与IEEE 802.15.4协议栈实战解析
  • 2026海口龙华区闲置黄金出手,把握实时金价好时机 - 肉松卷
  • CC27xx MCU异常处理与事件路由机制深度解析与实战
  • Ultralytics:解读ResNetBlock模块
  • 2026年企业桶装水三步升级降本两成高满意度 - 万相科技
  • 3分钟快速上手:Magpie-LuckyDraw免费抽奖系统完整指南
  • 金融领域双编码器Embedding优化实践与性能提升
  • 高效解决腾讯游戏卡顿:ACE-Guard Client资源限制器完整指南
  • 西安蓝田卫生间漏水维修检测正规防水补漏公司2026靠谱推荐 - 防水快讯
  • 线上缴费、一键报修不间断:广州燃气客服系统如何做到7×24小时不掉线?
  • AI量化交易策略:技术指标与另类数据结合实战
  • UART进阶应用:地址匹配、硬件流控与红外通信详解
  • 从 SAPUI5 升级不翻车说起,Compatibility Rules 在 Fiori 项目里的真实价值
  • 大模型PD分离技术:原理、优化与实践
  • 孩子天天练口算还是错?你可能缺的不是题量,而是一个会分析的学习系统
  • 电机驱动开发学习19. 霍尔 BLDC 三段式 FOC 启动算法
  • 基于SpringBoot+Vue大学生创业项目申报平台
  • GetQzonehistory:QQ空间说说备份的完整解决方案
  • Cortex-M33内存映射与TrustZone-M安全隔离实战解析
  • 微软开源Azure Linux:云原生操作系统的技术解析与实践指南
  • AM261x硬件加速器实战:CCS与AES引擎的编程详解与性能优化
  • 基于YOLOv8与红外热成像的森林火灾预警系统
  • 5个一线电路板维修真实案例:很多人修不好,不是手艺差,是思路错了
  • RAG系统性能调优:从检索到生成的优化策略
  • 动态对抗评估提升LLM鲁棒性的工程实践