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

原创 2018年01月04日 00:00:00

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

?wxfrom=5&wx_lazy=1

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

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

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

功能简介

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

  • 自动识别图像计算距离

  • 自动帮你点击屏幕

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6UjR0X4m88nNIricR31buOgelMQdpg0NW1yzmcAHmodOYDlzic2ePoeog

运行环境

  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. 图片分析

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

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

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

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

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6VMOL7a3Pu7VQCtUjkfrmC7diaO4icFNsgvgU7ysUmIo46g1NXPMDwdNA

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6EJMjuPVMgM6RmzEFZNEqYoI6AXXTbobCc4rP9sBg9iaBKKlZCvpWbsQ

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6GQ4hhAicAHgz6cMP3XJg6oZVPv9YxxyWqCtN8acau8swhPj2ME6tEMw

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

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

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

  adb shell input swipe x y x y time

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

工程结构

GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6eufgM8eUiaXxxduvy6CTCrDmgoMRSk7gt9jpDkXmAulxrFFyOgo38rA

代码详解

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

  1. 寻找棋子位置

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX69OQ3AAvrDgbZBcibG3GibfL7RvJou1Vn3KMcHSeOscvSNIbSGqhibVLog

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6RIze9UJGfj0vw9ILTyuibnMQMV2PsEhC8euO55GUTGzc4fDzw4XpG3A

    这样我们就得到了棋子的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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX66jibTxhY90RnRv5iahobdDDmyI7Avclea4OCVwV9HMpX7XfxIxU7DKmg

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

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

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

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6Sich46Kn8A0wRJKuChnibdvtBwGDPtfcNQJdcGo4esHAwzMlQ7KiaaqoA

    /**
        * 寻找色块顶点像素
        */

       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 。

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6uDV9rRh7J6JeLrqg4kWEpV2YrZF13w674oE5O7QicZ3spVHMrfDTUNA

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

      斜线的公式为 y=kx+b

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

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

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

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

    GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6LgecbcjtLfQdrIuFpwKOfVc5psevqQhuIGDNiaf4HCz56rspgSiaGI2Q

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

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

玩游戏小窍门

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

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

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

GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6D5Mneo979ET7EEgYUIYiaLic0wD9AenRpc2hIGsiafN0tiaabRQ9JQibBAA

广

GVyeDObNlrFk7sIjjm1WnpaVQpPsVoX6iarYAYA6t4g9Wj7uhnLFWpbMiaUcLib68oEwqNia1fNQO6GvUtPwnGblyA

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

GVyeDObNlrGRR82TzQDNQfKGWhomTbBEkh0aDoZiarVI8xZKkR0Co5qQ8pfVd7dlRp3hcMW4aohdXuL1WzjHPFA

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/OQjya206rsQ71/article/details/78970088

微信“跳一跳”外挂制作历程

微信“跳一跳”外挂制作历程 最近微信出了个“跳一跳”小游戏还挺火的,但是我这种手残人士,小手一滑,棋子就不知道飞哪儿去了。那我气啊,排行榜得拉到底才能看到我的名字,手残肯定不是一两天能解决的,那就写个...
  • shayuchaor
  • shayuchaor
  • 2018-01-02 16:50:59
  • 7176

微信小程序跳一跳的游戏辅助实现

0.前言 微信小程序跳一跳是个挺不错的游戏,但身为一个天生爱折腾的geek,还是忍不住挑战这游戏的上限。 效果如下动图,游戏开始,程序会自动识别小人的坐标,你只需点击要跳到的那一个方块,程序将自动算出...
  • rolan1993
  • rolan1993
  • 2018-01-02 18:02:18
  • 14234

做一个微信跳一跳的外挂

淘宝上好多卖跳一跳代练的,其实做一个很简单,不需要有安卓开发知识,不需要有图像识别知识,不需要有人工智能知识!重要的事情说三遍,都不需要。 简单说一下思路: 1.用adb连手机截图,命令是: ...
  • zhhz_zhhz
  • zhhz_zhhz
  • 2018-01-01 15:24:05
  • 2924

微信「跳一跳」带火小游戏,开发者如何快速上手?

点击上方“CSDN”,选择“置顶公众号”关键时刻,第一时间送达!作者 | 凌华彬、王哲责编 | 徐威龙在微信 6.6.1 版本中,给用户推送了“玩一个小游戏才是正经事”的首屏小游戏入口,一时间整个朋友...
  • csdnnews
  • csdnnews
  • 2018-01-09 00:00:00
  • 9980

CocosCreator如何制作微信小游戏

CocosCreator在1.8版本开始,就支持一键发布微信小程序,下面是详细的发布步骤: 1、在微信公众平台下载微信开发者工具;     地址:https://mp.weixin.qq.com/...
  • qq_16224121
  • qq_16224121
  • 2018-01-29 18:05:13
  • 2799

微信跳一跳外挂学习与自己写的代码和一些思路

其中模仿学习了 2017年最后一篇文章:微信小程序游戏"跳一跳"刷榜原理解析! http://blog.csdn.net/F0ED9cZN4Ly992G/article/details/78937...
  • LLBKWORLD
  • LLBKWORLD
  • 2018-01-06 21:44:20
  • 3204

JAVA实现微信跳一跳辅助

1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python环境各种模块缺失,报错不停,于是乎,使用Java重新实现了一下。...
  • lihushiwoa
  • lihushiwoa
  • 2017-12-31 17:01:07
  • 19625

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

http://blog.csdn.net/OQjya206rsQ71/article/details/78970088其实也不能说算是外挂吧,算是个游戏小助手吧,毕竟不能抓包,也不能直接修改分数(据说...
  • zdy0_2004
  • zdy0_2004
  • 2018-02-24 00:56:43
  • 112

微信小程序-小游戏文档入口

有木有像我一样笨的小朋友找不到微信小程序-小游戏文档入口.这里我贴给大家.刚发布的百度不好找呀. https://mp.weixin.qq.com/debug/wxagame/dev/index....
  • liukai6
  • liukai6
  • 2017-12-29 14:02:09
  • 584

微信跳一跳(游戏辅助小外挂C语言版)

相信微信跳一跳这个游戏大家应该都或多或少听过或者玩过,想必好多朋友看到自己好友们得高分自己却分数老是玩不高! 之前在这个游戏刚出来时候有人用Python写出了一个小外挂,随后网上各种各样的外挂包括物...
  • edc370
  • edc370
  • 2018-01-14 12:37:10
  • 1737
收藏助手
不良信息举报
您举报文章:教你如何自己写一个微信小游戏「跳一跳」外挂
举报原因:
原因补充:

(最多只允许输入30个字)