上几周更新微信后,进入欢迎界面就提示出让玩一把微信小游戏《跳一跳》。一向不爱玩游戏的我(除了经典QQ飞车、CS外),当时抱着没兴趣的态度简单看了下,没有玩。与朋友玩耍时,常听他们聊起这个小游戏,偶尔也在网页和微信公众号上看见些关于这个小游戏的一些话题,为了不落伍,我决定继续随大流一把。

于是乎玩了几把后,发现自己最高分才30来分,感觉咋这么容易就挂了,而打开朋友圈排名一看,咋都这么牛逼,居然有人能玩好几大百。于是问了下朋友,了解下有没有什么技巧,他们告诉我说有外挂(心里对那些玩的分数挺高的就没有那么崇拜了),于是乎我就在网上搜索了下关于跳一跳的相关外挂,看了下可谓是琳琅满目,啥语言的都有。

我先下了个github上排名第一的(地址为:https://github.com/wangshub/wechat_jump_game),某大神是用python写的,然后我快速过了遍,对于实现的算法部分没看懂,很尴尬。通过这件事让我对python的强悍又有了重新的认知,不愧是短小精悍的语言!

然后我暂时放弃了python版本的,选择了一个我目前最熟悉的语言版本的:JAVA

从github的列表中我迅速锁定了一个标题名为:腾讯微信跳一跳破解(目前最高19844分)的版本(地址为:https://github.com/burningcl/wechat_jump_hack),决定把它下下来,尝试一把,不愧又是大神写的,一把下来看着分数差不多了,在800来分时,我手动把它停掉了,据说如果跳的分数太高,不容易传上去。

顺利打下NO.1,首次装逼成功!

作为一名充满探索精神的程序猿,我决定还是要弄清其原理,因为这个小辅助看起来如此简单,之前我也从来没有对这种小应用研究过,于是我决定一定要搞明白这个JAVA版本跳一跳辅助的原理,就算是我的游戏辅助的helloWorld吧。

技术原理

在分别看了排名第一的python版和这个号称最高分为近2万分的代码后,发现他们有一个共同点,那就是截图与模拟点击。通过adb工具将安卓手机连接到电脑后,通过adb来完成这个操作。
用到的命令如下:
1.adb截图命令,通过adb shell执行screencap命令 将手机的当前屏幕进行截屏,并保存在sdcard下的screenshot.png位置
adb shell /system/bin/screencap -p /sdcard/screenshot.png

2.adb拉取图片命令,通过adb的pull命令拉取手机位于sdcard/screenshot.png的图片到电脑中

adb pull /sdcard/screenshot.png

3.adb滑动命令,通过input swipe命令去模拟滑动,其参数的意思为startX,startY,endX,endY,duration,也就是模拟触摸屏幕的开始与结束的横竖坐标,最后的参数duration代表按下的时间毫秒值,时间越短代表按的时间也就越少。

shell input swipe %d %d %d %d %d

通过以上分析,我们可以得知,在这个小辅助中起着最重要的命令是第3个swipe命令了。那么如何计算swipe中按下的值呢?

先观察下游戏,简单分析后,可化为如下初中数学题:

已知A、B两点。A点坐标为(startX,startY),B点坐标为(endX,endY),棋子速度为V(像素/毫秒)。
求棋子要从A点到达B点的时间。


看到这个问题是不是感觉很简单,求出两点间的距离S,再乘以速度V就搞定了!

两点间的距离直接用中学学的两点间的距离公式即可.如果忘了就百度下,比如这样:

通过上面的分析后,想必每位都已经明白了所谓跳一跳外挂的基本原理了。

如果你会安卓开发,那么就完全能用做出一个“半自动”的跳一跳辅助了,通过WindowManager在小程序的最上层加入一个自定义的层,然后用户通过最外层的点击来获取两点间的距离,然后再通过计算,算出距离所要花的时间,再调用input touchscreen swipe命令即可。

另外,这个跳一跳小程序让我想到了传说中的微信自动抢红包利器,它是基于AccessibilityService 实现的。单从整体看感觉和这个跳一跳差不多,仔细一想仿佛知道原因了。AccessibilityService 只能获取出安卓的控件,像view,各种layout这样的,而小程序这种应该获取不出来,所以就不能通过AccessibilityService 来实现

全自动版实现算法

通过上面的介绍,大家应该都知道了如何实现一个半自动的跳一跳辅助了。但身为一名优秀的程序猿,很难摆脱懒惰的本性!
如果不通过人工去寻找棋子A与下一步棋盘的坐标,而是通过程序自动识别那就完美了!使其完成辅助程序的全自动功能。
那么如何让程序通过最简单的方法去找到跳一跳游戏中的棋子和下一步的中心坐标呢?我也不知道,看了大神的JAVA实现代码后感觉他写的这种算法挺简单也挺容易理解的,在这里分享出来,与君共勉。

棋子坐标寻找算法

先观察游戏图片,从中可以得知:棋子的颜色RGB值为404386。那么我们就可以遍历整个图片,获取出棋子这个颜色的坐标集合。
再通过分析,找到棋子中心坐标点。其坐标X中心点大致应为棋子坐标中最小的X与最大的X坐标的中心点,Y坐标应为棋子座标中的最大Y点,也就是最高值。
可得棋子的最终搜索JAVA代码为:
    public static final int R_TARGET = 40;public static final int G_TARGET = 43;public static final int B_TARGET = 86;public int[] find(BufferedImage image) {if (image == null) {return null;}int width = image.getWidth();int height = image.getHeight();int[] ret = {0, 0};int maxX = Integer.MIN_VALUE;int minX = Integer.MAX_VALUE;int maxY = Integer.MIN_VALUE;int minY = Integer.MAX_VALUE;for (int i = 0; i < width; i++) {for (int j = height / 4; j < height * 3 / 4; j++) {//提高搜索速度,因为棋子只会存在于整个图的中部位置int pixel = image.getRGB(i, j);int r = (pixel & 0xff0000) >> 16;int g = (pixel & 0xff00) >> 8;int b = (pixel & 0xff);if (ToleranceHelper.match(r, g, b, R_TARGET, G_TARGET, B_TARGET, 16)) {maxX = Integer.max(maxX, i);minX = Integer.min(minX, i);maxY = Integer.max(maxY, j);minY = Integer.min(minY, j);}}}ret[0] = (maxX + minX) / 2 +3;ret[1] = maxY;System.out.println(maxX + ", " + minX);System.out.println("pos, x: " + ret[0] + ", y: " + ret[1]);return ret;}

下一步棋盘中心坐标寻找

棋子中心坐标A点有了,接下来就是下一步棋盘中心坐标B点。
搜索B点与搜索棋子的坐标方法很类似。
不同的是棋子的颜色是固定不变的,棋盘的颜色是可变的。
通过简单分析后,同样的,可将这个问题转化为如下图的数学题:
最后附上棋子下一步棋盘中心点搜索实现的具体代码:
/*** desc:棋盘位置搜索*/
public class BoardPositionSearcher implements PositionSearcher {private Logger logger = LoggerFactory.getLogger(this.getClass());private BottleFinder bottleFinder = new BottleFinder();private int[] myPos;public int[] getMyPos() {return myPos;}public void setMyPos(int[] myPos) {this.myPos = myPos;}@Overridepublic int[] seach(BufferedImage screenShotImg) {if (screenShotImg == null) {return null;}int width = screenShotImg.getWidth();int height = screenShotImg.getHeight();//先获取出0 200这一点的像素,即顶部某的一点int pixel = screenShotImg.getRGB(0, 200);int r1 = (pixel & 0xff0000) >> 16;int g1 = (pixel & 0xff00) >> 8;int b1 = (pixel & 0xff);Map<Integer, Integer> map = new HashMap<>();//一列一列地搜索,在map中放入遍历点像素在这一行中出现的次数for (int i = 0; i < width; i++) {pixel = screenShotImg.getRGB(i, height - 1);map.put(pixel, map.getOrDefault(pixel, 0) + 1);}//获取出存在于map中像素出现次数最多的像素int max = 0;for (Map.Entry<Integer, Integer> entry : map.entrySet()) {if (entry.getValue() > max) {pixel = entry.getKey();max = entry.getValue();}}int r2 = (pixel & 0xff0000) >> 16;int g2 = (pixel & 0xff00) >> 8;int b2 = (pixel & 0xff);//获取出游戏背景从顶到底的颜色RGB值int t = 16;int minR = Integer.min(r1, r2) - t;int maxR = Integer.max(r1, r2) + t;int minG = Integer.min(g1, g2) - t;int maxG = Integer.max(g1, g2) + t;int minB = Integer.min(b1, b2) - t;int maxB = Integer.max(b1, b2) + t;logger.trace(minR + ", " + minG + ", " + minB);logger.trace(maxR + ", " + maxG + ", " + maxB);int[] ret = new int[6];int targetR = 0, targetG = 0, targetB = 0;boolean found = false;//遍历寻找棋盘顶点坐标,在棋子坐标上方搜索,从游戏背景4分之一处开始搜索,提高速度for (int backgroundY = height / 4; backgroundY < myPos[1]; backgroundY++) {for (int backgroundX = 0; backgroundX < width; backgroundX++) {int dx = Math.abs(backgroundX - myPos[0]);int dy = Math.abs(backgroundY - myPos[1]);if (dy > dx) {//如果这一点到棋子X的距离比这一点到棋子Y的距离小,就跳出循环, WHY?continue;}//获取出扫描这一点的RGB值pixel = screenShotImg.getRGB(backgroundX, backgroundY);int r = (pixel & 0xff0000) >> 16;int g = (pixel & 0xff00) >> 8;int b = (pixel & 0xff);//如果这一点的RGB值不在屏幕背景色的区间内if (r < minR || r > maxR || g < minG || g > maxG || b < minB || b > maxB) {ret[0] = backgroundX;ret[1] = backgroundY;//则下一步的顶点坐标为这个点logger.trace("top, x: " + backgroundX + ", y: " + backgroundY);//遍历这个点向下5个高度的像素for (int k = 0; k < 5; k++) {pixel = screenShotImg.getRGB(backgroundX, backgroundY + k);targetR += (pixel & 0xff0000) >> 16;targetG += (pixel & 0xff00) >> 8;targetB += (pixel & 0xff);}//取出这个点的像素平均值targetR /= 5;targetG /= 5;targetB /= 5;found = true;break;}}if (found) {break;}}//判断是否为白点if (targetR == BottleFinder.TARGET && targetG == BottleFinder.TARGET && targetB == BottleFinder.TARGET) {return bottleFinder.find(screenShotImg, ret[0], ret[1]);}boolean[][] matchMap = new boolean[width][height];boolean[][] vMap = new boolean[width][height];ret[2] = Integer.MAX_VALUE;ret[3] = Integer.MAX_VALUE;ret[4] = Integer.MIN_VALUE;ret[5] = Integer.MAX_VALUE;Queue<int[]> queue = new ArrayDeque<>();queue.add(ret);while (!queue.isEmpty()) {int[] item = queue.poll();int i = item[0];int j = item[1];if (j >= myPos[1]) {
//                已搜索到棋子的Y值位置了,结束本次搜索,跳出循环continue;}if (i < Integer.max(ret[0] - 300, 0) || i >= Integer.min(ret[0] + 300, width) || j < Integer.max(0, ret[1] - 400) || j >= Integer.max(height, ret[1] + 400) || vMap[i][j]) {
//对于距离棋子坐标太远的跳出循环(即棋子坐标左、右、上、下的坐标),以及已经搜索过的坐标也跳出循环continue;}vMap[i][j] = true;pixel = screenShotImg.getRGB(i, j);int r = (pixel & 0xff0000) >> 16;int g = (pixel & 0xff00) >> 8;int b = (pixel & 0xff);//将每一个坐标点与棋盘顶点的RGB值比较matchMap[i][j] = ToleranceHelper.match(r, g, b, targetR, targetG, targetB, 16);if (i == ret[0] && j == ret[1]) {logger.trace(matchMap[i][j] + "");}//如果在棋盘面上if (matchMap[i][j]) {//获取出最左边的棋盘坐标if (i < ret[2]) {ret[2] = i;ret[3] = j;}//获取最上的棋盘坐标else if (i == ret[2] && j < ret[3]) {ret[2] = i;ret[3] = j;}//获取出最右边的棋盘坐标if (i > ret[4]) {ret[4] = i;ret[5] = j;}//获取出最上的棋盘坐标else if (i == ret[4] && j < ret[5]) {ret[4] = i;ret[5] = j;}//获取出最上的坐标点if (j < ret[1]) {ret[0] = i;ret[1] = j;}//将目标点左右上下的点放入队列中,实现递归queue.add(buildArray(i - 1, j));queue.add(buildArray(i + 1, j));queue.add(buildArray(i, j - 1));queue.add(buildArray(i, j + 1));}}logger.trace("left, x: " + ret[2] + ", y: " + ret[3]);logger.trace("right, x: " + ret[4] + ", y: " + ret[5]);return ret;}private int[] buildArray(int i, int j) {int[] ret = {i, j};return ret;}
}

完整代码请移步大神的github查阅。
最后感谢大神burningcl的代码,让我对JAVA图象代码有了基础的了解!感谢大神!

为了学习,我也burningcl大神在此代码的基础上加入了分数识别功能和一些中文注释,当程序跳到指定的期望的分数时程序将自动退出!项目地址为: wxJumpHelper

微信跳一跳辅助之JAVA版(最容易理解的算法)实现原理分析相关推荐

  1. 微信跳一跳java实现自动跳_安卓版微信跳一跳辅助(Java实现)

    效果图 已经看到网上有大神用各种方式实现了,我这是属于简易版ADB命令式实现. 操作方法 1.光标移动到起始点,点击FORM 2.光标移动到目标点,点击TO 3.小人已经跳过去了 原理说明 安装APP ...

  2. 100行微信跳一跳java_安卓版微信跳一跳辅助 跳一跳辅助Java代码

    安卓版微信跳一跳辅助,java实现,具体内容如下 已经看到网上有大神用各种方式实现了,我这是属于简易版ADB命令式实现. 操作方法 1.光标移动到起始点,点击FORM 2.光标移动到目标点,点击TO ...

  3. 微信跳一跳java实现自动跳_微信跳一跳辅助Java代码实现

    微信跳一跳辅助的Java具体实现代码,供大家参考,具体内容如下 1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python ...

  4. JAVA实现微信跳一跳辅助(手动)

    工具:total control . eclipse/java环境 . ADB 环境:1.1 total control 官网下载地址: http://tc.sigma-rt.com.cn/   下载 ...

  5. python跳一跳编程构造_python实现微信跳一跳辅助工具步骤详解

    说明 1.windows上安装安卓模拟器,安卓版本5.1以上 2.模拟器里下载安装最新的微信6.6.1 3.最好使用python2.7,python3的pyhook包有bug,解决比较麻烦 步骤 1. ...

  6. python微信公众号秒杀代码_微信跳一跳辅助python代码实现

    微信跳一跳辅助python代码实现 来源:中文源码网    浏览: 次    日期:2018年9月2日 [下载文档:  微信跳一跳辅助python代码实现.txt ] (友情提示:右键点上行txt文档 ...

  7. python hook pc微信_python实现微信跳一跳辅助工具步骤详解

    说明 1.windows上安装安卓模拟器,安卓版本5.1以上 2.模拟器里下载安装最新的微信6.6.1 3.最好使用python2.7,python3的pyhook包有bug,解决比较麻烦 步骤 1. ...

  8. python实现微信hook_python实现微信跳一跳辅助工具步骤详解

    说明 1.windows上安装安卓模拟器,安卓版本5.1以上 2.模拟器里下载安装最新的微信6.6.1 3.最好使用python2.7,python3的pyhook包有bug,解决比较麻烦 步骤 1. ...

  9. 微信跳一跳辅助php,微信跳一跳辅助python代码实现

    微信跳一跳辅助的python具体实现代码,供大家参考,具体内容如下 这是一个 2.5D 插画风格的益智游戏,玩家可以通过按压屏幕时间的长短来控制这个「小人」跳跃的距离.可能刚开始上手的时候,因为时间距 ...

最新文章

  1. 华为交换机ssh思科交换机_使用SSH或Telnet访问思科业务交换机CLI
  2. HDFS块文件和存放目录的关系
  3. 误操作数据库的一个方法
  4. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(2)
  5. jzoj5698-[gdoi2018day1]密码锁【贪心,差分】
  6. 使用java理解程序逻辑 第十二章_Java多线程中锁的理解与使用(二)
  7. 对数据库设计的一点感想
  8. java 获取指定日前的前一天
  9. python怎么把变量付给数组_使用Python将数组的元素导出到变量中(unpacking)
  10. linux 批量修改文件后缀名
  11. P12 | N-path filter (ISSCC2021 JSSC-2011-03)
  12. 安装“万能解码器”还原真实“解码”(纯以个人兴趣分析)
  13. 用户登录+页面跳转+后台首页实现
  14. HTML Canvas 刮刮卡抽奖效果的实现
  15. 银行间市场的USDCNY即期一天交易量到底有多少?
  16. 洛谷2448 无尽的生命[树状数组 离散化]
  17. 电脑连不上网络,怎么办?
  18. 罐头水果的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  19. 服务器修改和绑定mac地址,MAC地址绑定错误是为什么
  20. 项目时间管理的几种方法

热门文章

  1. 树莓派是网盘?nextcloud在树莓派上的应用
  2. linux下修改网卡MAC地址
  3. Win7安装Docker 1
  4. 射频领域你们如何管理测试夹具的?
  5. 全自动苹果CMS火车头采集器,苹果CMS火车头发布插件
  6. Linux解压压缩包到同名目录,里面的文件会自动覆盖吗?
  7. 程序员面试考察的5个方面
  8. C#获取微信打卡数据
  9. c语言素数筛法与分解素因数,质因数分解及代码:
  10. exdoll机器人_打造国内领先的定制化人工智能机器人品牌, EXDOLL新品惊艳亮相_TOM新闻...