【回复“1024”,送你一个特别推送】

其实也不能说算是外挂吧,算是个游戏小助手吧,毕竟不能抓包,也不能直接修改分数(据说之前可以直接抓包修改分数,不过这漏洞已经被微信官方修复),今天这个是 Android 同学可以非常容易看懂的一篇文章,是从 Android 的角度实现的,附带着技术原理分析和代码分析。

这个开源库已经被我同学分享到 GitHub 上,他自己很无聊,就写了这个东西和这篇文章,自己通过写代码实现高分也是玩的不亦乐乎,这就是程序员和普通玩家的区别吧。

开源库地址:https://github.com/xushanmeng/WechatJumpHelper

功能简介

用JAVA自动控制手机玩跳一跳

  • 自动识别图像计算距离

  • 自动帮你点击屏幕

  • 自动缓存图片,并在图片上标记一些识别结果,如下图:

运行环境

  1. JAVA,最低版本为7.0,官网下载

  2. adb驱动,官网下载(需要翻墙),或者到这里下载SDK-tools,其中就包含adb

  3. 安卓手机,目前已适配分辨率

  • 1600x2560

  • 1440x2560

  • 1080x1920

  • 720x1080

使用方法

有JAVA开发工具的同学可以直接运行java代码,便于代码调试,下面主要介绍运行已经打包好的jar包的方法

  1. 手机打开USB调试,并连接电脑

  • 打开USB调试方法,进入设置,找到开发者选项,打开并勾选USB调试

  • 如果没有开发者选项,进入关于手机,连续点击版本号7次,即可开启开发者选项

  • 通过下面的命令,运行Android.jar

    java -jar Android.jar

  • 根据手机分辨率选择跳跃系数,目前已适配机型:

    其他分辨率请自己微调。

    • 1600x2560机型推荐0.92

    • 1440x2560机型推荐1.039

    • 1080x1920机型推荐1.392

    • 720x1080机型推荐2.078

    原理说明

    1. 通过adb命令控制手机截图,并取回到本地

      adb shell screencap -p /sdcard/screen.png

      adb pull /sdcard/screen.png .

    2. 图片分析

    • 有靶点,即目标物体中心的白色圆点,则靶点中心为目标落点

    • 无靶点,但是纯色平面,或者规则平面,则平面中心为目标落点

    • 无靶点,又无纯色规则平面,但是左上和右上位置的斜率是固定的,可根据固定斜率的斜线和目标物体中心线的焦点计算落点

    • 根据棋子的颜色,取顶部和底部的特征像素点,在截图中进行匹配,找到棋子坐标

    • 由于目标物体不是在左上就是在右上,可以从上往下扫描,根据色差判断目标物体位置,其中又分为以下几种类型

    • 计算棋子坐标和目标落点的距离

    • 距离×跳跃系数=按压屏幕的时间,不同分辨率的手机,跳跃系数也有所不同

  • 通过adb命令,给手机模拟按压事件

    adb shell input swipe x y x y time

    其中xy是屏幕坐标,time是触摸时间,单位ms。

  • 工程结构

    代码详解

    这里将针对一些关键算法的代码进行解释

    1. 寻找棋子位置

      把截图放大,可以看到棋子顶部像素连成一条横线,那么我们通过颜色匹配,找到这一条线的始末位置,取中间位置,就得到了棋子的x坐标。

      棋子的底部也是一条横线,用颜色匹配,我们检测到相似颜色的最大y坐标,就是棋子底部了,不过考虑到棋子底部是个圆盘,我们把棋子的y坐标再往上提一些。

      这样我们就得到了棋子的xy坐标,下面是相关代码:

      /* 计算棋子位置 */Pixel piece = new Pixel();for (int i = TOP_BORDER; i < screenHeight - BOTTOM_BORDER; i++) {    int startX = 0;    int endX = 0;    for (int j = LEFT_BORDER; j < screenWidth - RIGHT_BORDER; j++) {        int red = Color.red(pixels[i][j].color);        int green = Color.green(pixels[i][j].color);        int blue = Color.blue(pixels[i][j].color);        if (50 < red && red < 55                && 50 < green && green < 55                && 55 < blue && blue < 65) {//棋子顶部颜色            //如果侦测到棋子相似颜色,记录下开始点            if (startX == 0) {                startX = j;                endX = 0;            }        } else if (endX == 0) {            //记录下结束点            endX = j;
      
                  if (endX - startX < PIECE_TOP_PIXELS) {                //规避井盖的BUG,像素点不够长,则重新计算                startX = 0;                endX = 0;            }        }        if (50 < red && red < 60                && 55 < green && green < 65                && 95 < blue && blue < 105) {//棋子底部的颜色            //最后探测到的颜色就是棋子的底部像素            piece.y = i;        }    }    if (startX != 0 && piece.x == 0) {        piece.x = (startX + endX) / 2;    }}//棋子纵坐标从底部边缘调整到底部中心piece.y -= PIECE_BOTTOM_CENTER_SHIFT;
    2. 寻找靶点

      所谓靶点,就是目标物体中心的那个小圆点,颜色值为0xf5f5f5

      那么我们只需要寻找颜色值为0xf5f5f5的色块就可以了,为了规避其他物体相近颜色干扰,我们可以限制色块的大小,正确大小的色块才是靶点。

      但是如何计算色块的大小呢,色块最顶端到最底端y坐标的差值我们作为色块的高度,同理,最左侧到最右侧x坐标的差值作为宽度,我们只需要查找这四个顶点的坐标就可以了。

      本来打算用凸包的Graham扫描算法,后来发现色块已经是凸包了,且边缘像素是连续的,那么我们按照一定顺序,遍历边缘像素,就可以在O(n^-2)的时间复杂度里,得到色块的顶点坐标了。

      我们从第一个像素点开始,寻找的顺序如图所示:

      /**     * 寻找色块顶点像素     */    public static final Pixel[] findVertexs(Pixel[][] pixels, Pixel firstPixcel) {        Pixel[] vertexs = new Pixel[4];        Pixel topPixel = firstPixcel;        Pixel leftPixel = firstPixcel;        Pixel rightPixel = firstPixcel;        Pixel bottomPixel = firstPixcel;        Pixel currentPixcel = firstPixcel;        //先把坐标置于左上角        while (checkBorder(pixels, currentPixcel)//判断是否超出图像边缘                && Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {//判断是否是相同颜色            currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];        }        while (checkBorder(pixels, currentPixcel)                && Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {            currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];        }        //寻找上顶点像素        while (checkBorder(pixels, currentPixcel)) {            if (Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];            } else if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x + 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x + 1];            } else {                topPixel = findCenterPixcelHorizontal(pixels, currentPixcel);                break;            }        }        //寻找右顶点像素        while (checkBorder(pixels, currentPixcel)) {            if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x + 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x + 1];            } else if (Color.compareColor(pixels[currentPixcel.y + 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y + 1][currentPixcel.x];            } else {                rightPixel = findCenterPixcelVertial(pixels, currentPixcel);                break;            }        }        //寻找下顶点像素        while (checkBorder(pixels, currentPixcel)) {            if (Color.compareColor(pixels[currentPixcel.y + 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y + 1][currentPixcel.x];            } else if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];            } else {                bottomPixel = findCenterPixcelHorizontal(pixels, currentPixcel);                break;            }        }        //寻找左顶点像素        while (checkBorder(pixels, currentPixcel)) {            if (Color.compareColor(pixels[currentPixcel.y][currentPixcel.x - 1], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y][currentPixcel.x - 1];            } else if (Color.compareColor(pixels[currentPixcel.y - 1][currentPixcel.x], firstPixcel)) {                currentPixcel = pixels[currentPixcel.y - 1][currentPixcel.x];            } else {                leftPixel = findCenterPixcelVertial(pixels, currentPixcel);                break;            }        }        vertexs[0] = leftPixel;        vertexs[1] = topPixel;        vertexs[2] = rightPixel;        vertexs[3] = bottomPixel;        return vertexs;    }

      得到了四个坐标点,我们就可以计算色块的中点了,也就是目标落点。

      对于没有靶点,但是落点是规则平面的,也可以用类似算法。

    3. 斜率计算对于没有靶点,又不是规则平面的,我们怎么计算落点呢,这时候就要用到斜率了。

      可以看得出来,每次左上角或右上角出现的物体,针对当前物体的方向都是一样的,也就是两个物体中心的连线,斜率是固定的。

      基本所有的目标物体,最顶点像素中点的x坐标,都是在物体中间,我们至少先得到了目标物体x坐标了,记为des.x ,接下来要求des.y 。

      如上图所示,计算过程如下:

      斜线的公式为 y=kx+b

      那么,在棋子坐标上有 piece.y=k*piece.x+b

      在目标落点坐标上有 des.y=kdes.x+b

      代入得到 des.y=k*(des.x-piece.x)+piece.y

      然而这种算法还是有偏差的。

      可以看到,同样的斜率,如果棋子的位置有偏差,计算出来最终落点还是会有偏差的。

      代码解析就先讲这么多,希望有大神可以提出更好的解决方案。

    玩游戏小窍门

    1. 连续的落到物体中心位置,是有分数加成的,最多跳一次可以得几十分

    2. 井盖、商店、唱片、魔方,多停留一会,有音乐响起后也是有分数加成的

    那么看一下程序员的朋友圈有多残酷吧

    广

    2018年前端最新技术栈,资深架构师亲自讲解,剖析原理深挖底层,带领初学者无压力入门到精通,还有开发工具包>程序员面试技巧等海量资料实时更新,即日起免费赠送!添加客服小姐姐QQ( 846136557 )获得领取资格吧~

教你如何自己写一个微信小游戏「跳一跳」外挂相关推荐

  1. 微信小游戏「跳一跳」外挂(java版)

    image 其实也不能说算是外挂吧,算是个游戏小助手吧,毕竟不能抓包,也不能直接修改分数(据说之前可以直接抓包修改分数,不过这漏洞已经被微信官方修复),今天这个是 Android 同学可以非常容易看懂 ...

  2. 微信小游戏「跳一跳」技术手段高分秘籍实现

    元旦赠书活动还在继续中,欢迎点击下方链接参与: 赠书一:<函数响应式领域建模> 赠书二:<Java函数式编程> 赠书三:<高可用架构> 最近这两天,从前天微信最新版 ...

  3. scratch跳一跳游戏脚本_cocos creator制作微信小游戏「跳一跳」

    一.游戏的分析(之前没有接触过小游戏,制作的思维还停留在大型ARPG游戏大家共同协作的想法里,但是小游戏讲究小而全,大部分时间是一个人独立开发,所以需要迫使自己养成看到小游戏先拆分细化的思想) 二.一 ...

  4. 当微信遇上 10 万战绩的「跳一跳」外挂,程序员还能“逍遥”多久?

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! 一款热门游戏,普通用户玩的是乐趣,而对于程序员来说,走的是非常人之路,以各种花样技术方法获取 ...

  5. 微信小程序游戏「跳一跳」高分秘籍

    饱受争议的微信小程序从今年1月份上线到现在已经快一年了,被寄予厚望的小程序在这一年却并没有达到曾经预期的高度,反而是一直不温不火. 曾经有现象级的刷屏的小程序:匿名聊聊,本以为这会是小程序的新玩法.爆 ...

  6. 微信小程序python_用python一步一步教你玩微信小程序【跳一跳】

    12月28日,微信上线了小游戏「跳一跳」,瞬间成了全民游戏,如何牢牢占据排行榜的第一位呢?用Python帮助你,Python真的无所不能. 作为技术出身的我们,是不是想用技术改变排名呢? 注意:本文适 ...

  7. python玩微信小程序游戏_用python一步一步教你玩微信小程序【跳一跳】

    12月28日,微信上线了小游戏「跳一跳」,瞬间成了全民游戏,如何牢牢占据排行榜的第一位呢?用Python帮助你,Python真的无所不能. 作为技术出身的我们,是不是想用技术改变排名呢? 注意:本文适 ...

  8. python玩微信小程序游戏_016 用python一步一步教你玩微信小程序【跳一跳】

    12月28日,微信上线了小游戏「跳一跳」,瞬间成了全民游戏,如何牢牢占据排行榜的第一位呢?用Python帮助你,Python真的无所不能. 作为技术出身的我们,是不是想用技术改变排名呢? 注意:本文适 ...

  9. 「跳一跳」两年后,广告“杀死”游戏小程序?

    文 | 陈选滨 来源丨智能相对论(ID:aixdlun) 两年前,一款游戏小程序「跳一跳」火爆朋友圈,几乎所有的微信好友都在玩这款小游戏,刷新好友排行榜的分数.一时间,微信的社交圈子被成功引爆,游戏类 ...

最新文章

  1. wxWidgets:wxGridEvent类用法
  2. MySql轻松入门系列——第一站 从源码角度轻松认识mysql整体框架图
  3. 深夜,学妹说她想做Python数据分析师
  4. Codeforces Round #704 (Div. 2) E. Almost Fault-Tolerant Database 思维
  5. js中报错 ajax不存在,AJAX
  6. 浅谈“三层结构”原理与用意(转帖)
  7. 《数据库实验》实验一:建立数据库和基本表结构
  8. PowerBuilder开发简单计算器
  9. PIC单片机应用开发实践教程(四): MPLAB X IDE Debug
  10. 牛人面对面|专访Testin(云测)总裁徐琨
  11. 手写原笔迹输入_手写原笔迹输入SurfacePro使用更轻松
  12. 积分运算电路的设计方法详细介绍
  13. 关于BOM表的一些事
  14. 博士申请 | 新加坡科技设计大学段凌杰教授招收人工智能全奖博士生
  15. vSphere Client无法连接到Vcenter
  16. 学生管理系统课程设计
  17. 有关UDE(Unsupervised Domain Expansion)以及UDA,DG的思考与调研
  18. Kitti数据集标签中yaw角在不同坐标系的转换
  19. 第二十六章 数论——欧拉函数(详解与证明)
  20. 为什么我charles抓包带了给锁_使用Charles抓包

热门文章

  1. Pytorch:一些常用代码
  2. Qcom平台 Camera 之常见错误和问题
  3. 1.8正版生存服务器,我的世界1.8纯净版
  4. windows开机自动运行bat文件
  5. GitChat·人工智能 | 肿瘤医疗影像 AI 识别技术实践
  6. 《人类简史》五、监狱高墙——想象构建的秩序
  7. 一个刚进入公司的初级java工程师
  8. python的os删除文件或者文件夹
  9. Python数据分析 | (27) 重塑和轴向旋转
  10. 江西用计算机写作文说课稿,信息技术说课稿范文(精选5篇)