十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

用Python和OpenCV实现微信跳一跳自动脚本:ADB控制与图像识别全解析

用Python和OpenCV实现微信跳一跳自动脚本:ADB控制与图像识别全解析 简介这是一份面向微信小游戏《跳一跳》的 Python 自动化脚本已针对安卓设备完成适配适合想学习自动化控制、图像识别和简单物理计算的 Python 开发者从零基础到中级均可参考。压缩包内共 40 个文件24 个 JSON 配置涵盖多种分辨率与机型参数另有 5 个 Python 源码、4 个 pyc 编译文件、3 张示例截图和 1 个说明文档整包约 340KB结构轻量。脚本通过截屏识别棋子与目标平台结合距离与按压时长的物理计算模拟连续跳跃宣称能稳定达到 1000 分以上针对不同设备的分辨率参数已单独配置便于直接替换使用相比简单录制点击在多种手机上都有较高稳定性。资源目前已有 1115 人学习下载下载后可直接查看完整脚本、多机型配置、依赖清单和调试截图既能快速体验自动游戏效果也能从中了解安卓自动化、图像处理、坐标换算与异常排查的实际思路适合作为 Python 自动化方向的练手项目。 如果你玩过微信里那个“跳一跳”一定对手指按压时长的微妙手感记忆犹新。这款小游戏火了之后“跳一跳python脚本”就成了很多Python爱好者入坑图像处理和移动端自动化时的第一个练手项目。它做的事情并不复杂程序自动截取手机屏幕识别当前棋子和下一个落脚方块的位置算出两点距离再按比例换算成按压时长通过ADB模拟手指长按让棋子跳到目标方块然后循环下去。我最早接触这个脚本时以为就是某段现成代码跑起来刷个分而已。真正动手之后才发现这里面的技术链路非常完整ADB命令、图像预处理、颜色识别、轮廓检测、坐标计算、自动化控制几乎把计算机视觉和移动自动化的基础过了一遍。这篇文章不打算只给你贴一段源码而是把整套思路、关键代码和调试过程中踩过的坑都摊开讲。刚入门Python的同学可以照做跑通第一版已经写过基础脚本的朋友可以重点关注后面的参数标定和识别漂移问题。1. 项目概述1.1 跳一跳Python脚本到底做了什么普通玩家玩跳一跳靠手指在屏幕上按住小人按压时间越长跳得越远。脚本要替代的是“眼睛判断距离、大脑估算时长、手指执行按压”这个闭环。对应到程序里就是三个动作通过ADB截图获得当前游戏画面用OpenCV分析图像找到棋子坐标和目标方块坐标计算两点距离通过ADB模拟长按按压时长与距离成正比。这三个动作循环执行就形成了自动玩游戏的能力。从工程视角看这是一个典型的“感知—决策—执行”闭环和自动驾驶或者机器人的工作方式是同构的只不过这里的所有决策全部发生在Python进程里外部硬件只负责截图和执行触摸事件。1.2 为什么这个项目值得上手第一它足够小。整个脚本可以控制在100行以内却涉及GUI自动化最常见的几个环节。第二反馈特别直观识别准不准、跳得准不准一眼就能看出来很适合调参练手。第三它逼着你理解“屏幕坐标”和“物理时间”之间换算这是很多自动化脚本都会遇到的坎。与其啃一堆理论不如直接用这个游戏把整个流程跑通。当时我写这个脚本最大的感受是OpenCV那些函数单独看都不难但真正组合起来才知道每一步都会引入误差而误差是会在链路里传递的。比如棋子坐标偏了3个像素目标坐标偏了5个像素最终按压时间可能就差出来十几毫秒反映到跳跃距离上就是一次失误。这种“从闭环里找误差”的体验是单纯看教程完全体会不到的。1.3 先明确脚本的适用边界得先说句实在话这类脚本如果拿到正式游戏里刷分既破坏其他玩家体验也违反游戏规则可能带来账号风险。我个人把它定位成“本地练手项目”和“图像处理教学案例”跑通之后拆掉也不可惜。希望你看完这篇文章重点不是拿它去刷多高的分数而是把里面的技术点吃透后面迁移到正经的自动化测试、数据采集工具里价值要大得多。2. 核心原理拆解2.1 屏幕信息怎么采集脚本怎么获得游戏画面Android手机提供了ADB调试桥Android Debug Bridge。电脑通过USB连上手机后可以执行命令行操作。截图命令是adb exec-out screencap -p screen.png这条命令直接把手机截屏的PNG数据输出到电脑本地文件比“先执行adb shell screencap保存到手机再adb pull拉到电脑”少了一步速度更快对后续循环操作更友好。Windows下如果发现重定向出来的图片打不开多半是控制台把二进制流做了转换这时可以改用adb shell screencap -p /sdcard/screen.png再adb pull两条路都行。拿到图片只是第一步更重要的问题是Python怎么读取。OpenCV的cv2.imread可以直接读取PNG文件如果希望实时性更高也可以把图片作为字节流直接读进cv2.imdecode。在循环里复用同一张文件名配合os.system调用基本能把一次截图耗时控制在200ms内。2.2 图像识别在这里扮演什么角色OpenCV在跳一跳脚本里的工作是回答两个问题棋子在哪目标方块在哪。棋子的识别相对简单。截图中棋子通常由白色圆点、深色身体和底部底盘组成和背景的对比度比较明显。可以通过cv2.inRange按颜色范围生成掩码再用cv2.findContours找轮廓轮廓外接矩形中心基本就是棋子位置。更稳妥的做法是在HSV色彩空间里过滤因为HSV对光线亮度变化没那么敏感。目标方块识别会麻烦一点。游戏的方块有很多种颜色同一局里相邻方块的颜色可能接近背景又有渐变。常见处理思路是先用高斯模糊平滑画面然后用Canny边缘检测找轮廓再按面积、位置过滤出“在棋子右侧、面积合适”的四边形轮廓取它的顶部中心作为落点。这里有无数种变体核心原则只有一个找一个在画面中稳定、可重复计算的特征点而不是完美还原整个游戏画面。2.3 距离和按压时间的关系假设棋子坐标为(x1, y1)目标方块中心为(x2, y2)平面距离就是欧氏距离distance sqrt((x2-x1)^2 (y2-y1)^2)接下来关键在于要把“像素距离”换算成“按压毫秒数”公式可以写成press_time distance * kk就是按压系数单位为毫秒/像素。为什么可以近似线性因为游戏里按压时间决定小人跳跃距离物理引擎在中等跳跃范围内基本呈线性关系。不过不同手机屏幕dpi不同同一个k值在不同分辨率上表现会差很多。所以脚本里最需要调整的通常就是k。有人觉得线性不够准尝试用二次函数拟合。实际体验下来在跳一跳这种距离跨度有限的场景里线性已经足够稳定非线性拟合反而容易在边界区域过拟合。先保证识别稳、坐标准比强行优化按压函数收益更大。3. 环境准备3.1 Python和依赖库安装我用的是Python 3.8以上版本。安装依赖只需要三个库pip install opencv-python numpynumpy用于数组运算opencv-python用于图像处理。如果你还需要便捷的数学运算可以再加scipy但最小依赖其实就这两个。不要一开始就装一堆库避免环境混乱。这里多说一句Python环境如果没配好后面所有代码都会跑得很痛苦。Windows用户装完Python后记得在安装界面勾选“Add Python to PATH”否则命令行里输入python会提示找不到命令。装完依赖可以用一行命令验证python -c import cv2, numpy; print(cv2.__version__)能正常输出版本号说明图像处理环境没问题。3.2 ADB工具配置ADB不需要安装整个Android Studio下载Platform-Tools压缩包解压后把里面的adb目录加到系统PATH即可。手机端需要开启开发者选项和USB调试连接电脑后第一次运行adb devices手机会弹出“允许USB调试”的授权框确认即可。如果你没有真机也可以用安卓模拟器。模拟器通常自带ADB接口比如某些模拟器通过adb connect 127.0.0.1:7555连接。用模拟器开发的好处是调试方便坏处是分辨率、性能和真机有差别k值需要重新标定。所以我建议有条件的同学直接用真机做画面效果更贴近实际。3.3 环境验证配置完成后先跑一个简单命令确认链路通adb devices adb exec-out screencap -p test.png如果test.png能正常打开说明截图链路可用。接着手动打开跳一跳让游戏停留在开始界面或对局中再运行这段命令截一张图用于后续图像调试。这一步非常重要很多识别不准的问题都是因为拿了一张模拟器截图去调真机参数或者反过来。4. 实操实现4.1 第一步截图与加载实际代码里可以封装一个截图函数import os import cv2 def pull_screenshot(): os.system(adb exec-out screencap -p screen.png) return cv2.imread(screen.png)Windows上如果图片打不开检查一下是否用了cmd的重定向cmd默认会把输出按文本处理。解决办法是换powershell的cmd /c或者直接改用两步命令。这个细节我在多台电脑上踩过Windows用户尤其要注意。读取到图像后建议顺手打印尺寸和一小块区域的颜色值确认图像完整。很多识别问题到最后都发现是截图文件损坏或者分辨率不对而不是算法本身有问题。4.2 第二步识别棋子位置很多开源脚本用模板匹配预先裁剪一张棋子小图然后在整张截图中找匹配位置。模板匹配的优点是实现快缺点是换手机、换分辨率、换游戏版本后模板可能失效。我更推荐用颜色和形状做动态识别。一个比较稳的思路在HSV空间里提取“棋子下方深色底盘”区域。代码骨架import numpy as np def find_player(img): hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) mask cv2.inRange(hsv, lower_color, upper_color) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, np.ones((5, 5), np.uint8)) contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if not contours: return None c max(contours, keycv2.contourArea) x, y, w, h cv2.boundingRect(c) return x w // 2, y h // 2这里的lower_color、upper_color是HSV阈值不同截图差异很大。我的做法是先用OpenCV的取色工具在当前截图上点选棋子底部的颜色读取HSV值再往上下各偏移几十作为阈值范围。别指望一个固定颜色走天下白天、夜间的亮度都不一样。4.3 第三步识别目标方块目标方块识别我习惯分三步走预处理、找轮廓、筛选。def find_target(img): h, w, _ img.shape roi img[int(h*0.2):int(h*0.8), int(w*0.2):int(w)] gray cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) blurred cv2.GaussianBlur(gray, (5, 5), 0) edges cv2.Canny(blurred, 50, 150) contours, _ cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选轮廓并返回目标点筛选条件通常包括轮廓面积不能太小、外接矩形宽高比例接近正方形、矩形中心在当前棋子的右上方。符合条件的候选点中取离棋子最近的一个作为目标落点。这里解释一下为什么要取最近因为跳一跳永远只跳到下一个方块不会跳越级所以“离当前棋子最近且符合方块特征的候选”就是目标。因为Canny边缘在方块边缘处往往会有断口可以先做一次形态学闭运算把断口连起来。轮廓不是完全矩形也没关系外接矩形的中心点已经足够接近目标中心。如果识别结果总是偏左或偏右可以检查是不是把方块侧面的阴影也算进去了这种情况把ROI区域往中间收一点就能改善。4.4 第四步计算距离并模拟按压拿到两个坐标后执行按压def jump(start_x, start_y, end_x, end_y, press_time): os.system(fadb shell input swipe {start_x} {start_y} {end_x} {end_y} {press_time})input swipe本意是模拟滑动但GestureDuration大于0且起点终点相同时效果就是“按压该点一段时间”。所以可以固定取屏幕中心点作为swipe的起终点只改变时长。不要用(0,0)作为起点某些设备对屏幕外坐标的处理不一致会导致按压无效。press_time的计算就是前面的公式。注意int(distance * PRESS_RATIO)后传给命令毫秒级整数不要传浮点数。4.5 第五步循环控制核心循环import time while True: img pull_screenshot() h, w, _ img.shape player find_player(img) target find_target(img) if player is None or target is None: print(识别失败停止) break dx target[0] - player[0] dy target[1] - player[1] dist (dx*dx dy*dy) ** 0.5 press_time int(dist * PRESS_RATIO) jump(w//2, h//2, w//2, h//2, press_time) time.sleep(1.5)每次跳跃后sleep 1到2秒等棋子彻底落定再截图。sleep太短会导致截图抓到空中状态坐标识别全乱。还可以加一个失败保护连续3次识别失败就退出避免无限循环把电量耗光。这里PRESS_RATIO是全局变量需要在前面定义好建议初始设为1.3左右。5. 参数调优与问题排查5.1 按压系数的标定方法k值怎么标定最笨但最有效的办法是“手动试跳”。把PRESS_RATIO打印出来观察初始给1.3跑一次记录棋子落在目标方块前/后多少像素。如果跳过头了说明k偏大减到1.2左右如果跳不到说明k偏小加到1.4。每次调整幅度不要超过0.05因为误差并不是线性的。这里也提供一种更系统的做法先记录20组实际距离和理想按压时间用最小二乘法拟合出斜率。每次跳跃后自己判断是否落在中心附近把“judged good”的数据点收进来重新拟合。跑几十局后k会收敛到一个稳定值。实测中大多数1080x1920的手机k在1.3到1.5之间但这不是万能值。5.2 常见问题速查现象可能原因处理办法adb devices看不到设备USB调试没开/驱动异常重新拔插检查授权弹窗截出来的图是黑屏手机锁屏或游戏不在前台解锁并保持游戏画面棋子识别到了错误位置HSV阈值范围过宽截一张当前图重新取色目标方块找了半天找不到Canny阈值不当/方块颜色接近背景调整Canny上下阈值增加形态学闭运算每次跳跃都偏离一段固定距离PRESS_RATIO不准按5.1的方法重标循环跑几分钟就停了识别连续失败触发保护打印中间变量看是哪一步识别失败模拟器坐标偏移模拟器改变了逻辑分辨率固定模拟器分辨率重新标定所有参数5.3 实操中的避坑心得第一个坑别在游戏后台有弹窗或通知栏的时候跑通知会改变画面结构识别率骤降。开发时最好开勿扰模式。第二个坑调试阶段一定把每帧的识别结果存成图片画上检测框再保存。我习惯把结果写到debug目录跑完一轮翻图片比盯着黑窗口日志直观得多。第三个坑按压后至少要等1.5秒。快速连续按压会让游戏画面处于动画中间态下一帧识别很容易失败。宁愿慢一点也不要追求极限连跳。第四个坑脚本可以绑定窗口标题之类的额外逻辑但没必要。这类小游戏脚本真正难的是识别和画质差异不是流程控制。6. 后续扩展6.1 从游戏脚本到自动化测试跳一跳脚本本质上是ADB加OpenCV的联合使用。这套组合我在实际工作中也经常用到比如自动化测试中判断App某个界面是否加载出来用模板匹配找关键按钮或者写个小工具批量采集指定App的截图做视觉回归。游戏里的识别经验可以无缝迁移。更进一步的玩法是把识别部分单独拆出来做成一个通用工具库。跳一跳的棋子识别本质是“在固定背景中找一个特定颜色和形状的目标”这种需求在工业质检、商品识别、图像采集里非常常见。你在这个项目里写的find_player和find_target稍微改改参数就能变成“识别画面上某个红色按钮位置”的函数。6.2 给想练手的人一点建议如果你现在准备动手实现我的建议是别急着把代码写完整。先手动截图存个十几张不同场景的画面研究一下游戏里棋子和方块在各种光照下的颜色变化把识别方案想清楚再写代码。调试过程中多利用debug图多打日志。在你把k值标定完、让脚本连续跳二三十下不出错的那一刻你会对“图像处理”和“自动化控制”这两个词的理解比看书一个月都深。本文还有配套的精品资源点击获取
返回列表