一、前言

(Java代码的实现是基于另外一篇博客,我精简了计算方法而成,参考博客地址http://blog.csdn.net/lihushiwoa/article/details/78942322)

先说一说我的感受,之前觉得能做出做出辅助工具的技术要求一定很高,然而当自己真正分析原理并且动手实现之后发现门槛没有那么高。

想做这个工具首先得知道adb是什么,其次是会一门编程语言。我了解adb之后瞬间觉得思路豁然开朗。

adb是Android Debug Bridge。他的作用是可以通过在计算机cmd输入命令控制Android手机,比如马上要用到的效果----模拟实现触控屏幕和触控多长时间。所以你在java代码里控制adb命令是可行的。

二、思路与原理

想象一下手动能让棋子命中下一个platform的场景:

1:测量棋子到目标坐标的距离S;

2:按压时间T=S*时间系数;(时间系数:单位位移的用时,200ms的n倍,多次尝试的大致确认)

然后你按屏幕时间T就可以了。

在本代码中我发现每个跳板的连线与竖直方向大约呈60°夹角(跳板和跳板虽然是60°,但是棋子不一定与目标是60°角关系呀?没关系,经过测试与棋子的角度没太大关系),所以如果我们知道棋子和目标点的距离就可以算S了。

代码实现也一样:

1:adb命令截屏,存放到指定文件夹。adb命令分别是:

adb shell screencap -p /sdcard/current.png

adb pull /sdcard/current.png  d:/jump_screencapture

2:扫描棋子的X轴坐标。

图片是一个个像素点组成,从上往下遍历每一行像素点,如果某像素点的R、G、B值在棋子的RGB值区间(R∈(50,60),G∈(53,63),B∈(95,110)),那么可以确定该像素点在棋子内了,然后记下这是第几个(halmaXCount),并且计算横坐标的和halmaSum+=halmaSum(原理:多次测量取平均值,精确棋子的X轴坐标)。

3:扫描目标跳板的横坐标。原理与扫描棋子相似,但又不同。

原理:由于跳板是左右对称的,也就是说假如目标跳板的上表面是标准的菱形,那么一旦遍历到菱形上方的顶点,那么该顶点的X坐标就是目标跳板上表面中心的X坐标。

不同之处是:遍历完目标调班的首行像素点便停止,(缺点:样本空间略小,可能导致目标坐标不精确,留日后优化。)。记录每行首个像素点的RGB值之后,在接下来的遍历中如果发现本行与首个像素点RGB差异太大,则认为该像素点已经在目标跳板之内。找到所有不同于第一个像素点的X坐标求平均数,然后结束。

4:计算棋子与目标点的距离,和按压时间。

三、ADB配置

ADB主要是Path配置,配置完,在cmd中输入adb,如下图便是配置成功。需要的可以去http://download.csdn.net/download/thread_cooperation/10212920下载

四、代码实现

注意:不要在开发工具里跑,可能无法调用ADB。在cmd中是可行的。

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;  import javax.imageio.ImageIO;  /** * 参考CSDN*  @link <a target="_blank" href="http://blog.csdn.net/lihushiwoa/article/details/78942322">http://blog.csdn.net/lihushiwoa/article/details/78942322</a> *  * 说明:本版本是在上述参考CSDN的基础上,精简计算而成,目前支持分辨率1920x1080的安卓机(在下没有其他分辨率的手机用于测试)*  * 跳一跳辅助 * @author ykq */
public class Jump {  private static final String IMAGE_NAME              = "current.png";  private static final String STORE_DIR               = "d:/jump_screencapture";  //截图的数量上限  private static final int    imageLengthLength       = 5;  //存放图片的数组private static final long[] imageLength             = new long[imageLengthLength];  private final RGBInfo       rgbInfo                 = new RGBInfo();  //adb脚本private final String[]      ADB_SCREEN_CAPTURE_CMDS =  { "adb shell screencap -p /sdcard/" + IMAGE_NAME,  "adb pull /sdcard/current.png " + STORE_DIR };  //截屏中游戏分数显示区域最下方的Y坐标,300是 1920x1080的值,根据实际情况修改  private final int           gameScoreBottomY        = 310;  //按压的时间系数,可根据具体情况适当调节  private final double        pressTimeCoefficient    = 1.37;//按压的起始点坐标,也是再来一局的起始点坐标  private final int           swipeX                  = 550;  private final int           swipeY                  = 1580;  //棋子的宽度,从截屏中量取,自行调节  private final int           halmaBodyWidth          = 74;//csc(pi/6)private final static double         proportion              = 2/Math.sqrt(3);public static void main(String[] args){  try{  File storeDir = new File(STORE_DIR);  //构建文件目录if (!storeDir.exists()) {  boolean flag = storeDir.mkdir();  //创建文件夹if (!flag) {  System.err.println("创建图片存储目录失败");  return;  }  }  Jump jumpjumpHelper = new Jump();  //执行次数  int executeCount = 0;  for (;;){  //执行ADB命令,获取安卓截屏  jumpjumpHelper.executeADBCaptureCommands();  File currentImage = new File(STORE_DIR, IMAGE_NAME);  if (!currentImage.exists()){  System.out.println("图片不存在");  continue;  }  long length = currentImage.length();  imageLength[executeCount % imageLengthLength] = length;  //查看是否需要重新开局  jumpjumpHelper.checkDoReplay();  executeCount++;  System.out.println("当前第" + executeCount + "次执行!");  //获取跳棋和底板的中心坐标  int[] result = jumpjumpHelper.getHalmaAndBoardXYValue(currentImage);   //Halma跳棋if (result == null){  System.out.println("The result of method getHalmaAndBoardXYValue is null!");  continue;  }  int halmaX = result[0];  int boardX = result[1];  System.out.println("halmaX: " + halmaX + "  ****  " + "boardX: " + boardX);  //计算跳跃的距离  double jumpDistance = Math.abs(boardX-halmaX)*proportion;jumpjumpHelper.doJump(jumpDistance);  //每次停留2.5秒  TimeUnit.MILLISECONDS.sleep(2500);  }  }  catch (Exception e){  e.printStackTrace();  }  } /** * 获取跳棋以及下一块跳板的中心坐标 * * @return * @throws IOException */  public int[] getHalmaAndBoardXYValue(File currentImage) throws IOException{  BufferedImage bufferedImage = ImageIO.read(currentImage);  int width = bufferedImage.getWidth();  int height = bufferedImage.getHeight();  System.out.println("宽度:" + width + ",高度:" + height);  int halmaXSum = 0;  int halmaXCount = 0;  int boardX = 0;  //从截屏从上往下逐行遍历像素点,以棋子颜色作为位置识别的依据,最终取出棋子颜色最低行所有像素点的平均值,即计算出棋子所在的坐标  for (int y = gameScoreBottomY; y < height; y++){  for (int x = 0; x < width; x++){  processRGBInfo(bufferedImage, x, y);  //获取指定坐标的RGB值 int rValue = this.rgbInfo.getRValue();  int gValue = this.rgbInfo.getGValue();  int bValue = this.rgbInfo.getBValue();  //根据RGB的颜色来识别棋子的位置,  if (rValue > 50 && rValue < 60 && gValue > 53 && gValue < 63 && bValue > 95 && bValue < 110){  halmaXSum += x;  halmaXCount++;  }  }  }  if (halmaXSum != 0 && halmaXCount != 0){  //棋子底行的X坐标值  int halmaX = halmaXSum / halmaXCount;  //从gameScoreBottomY开始,获取棋子的x坐标for (int y = gameScoreBottomY; y < height; y++){  processRGBInfo(bufferedImage, 0, y);  //每行第一个像素的RGB(获取指定坐标的RGB值 )int lastPixelR = this.rgbInfo.getRValue();  int lastPixelG = this.rgbInfo.getGValue();  int lastPixelB = this.rgbInfo.getBValue();  //只要计算出来的boardX的值大于0,就表示下个跳板的中心坐标X值取到了。  if (boardX > 0){  break;  }  int boardXSum = 0;  int boardXCount = 0;  for (int x = 0; x < width; x++){  processRGBInfo(bufferedImage, x, y);  int pixelR = this.rgbInfo.getRValue();  int pixelG = this.rgbInfo.getGValue();  int pixelB = this.rgbInfo.getBValue();  //处理棋子头部比下一个跳板还高的情况      跳过棋子所在的x轴区域不遍历(防止检索到棋子的颜色)if (Math.abs(x - halmaX) < halmaBodyWidth){    //abs绝对值continue;  }  //从上往下逐行扫描至下一个跳板的顶点位置,下个跳板可能为圆形,也可能为方框,取多个点,求平均值  if ((Math.abs(pixelR - lastPixelR) + Math.abs(pixelG - lastPixelG) + Math.abs(pixelB - lastPixelB)) > 8){   boardXSum += x;  boardXCount++;  }  }  if (boardXSum > 0){  boardX = boardXSum / boardXCount;  }  }  if (boardX > 0){  int[] result = new int[2];  //棋子的X坐标  result[0] = halmaX;  //下一块跳板的X坐标    result[1] = boardX;  return result;  }  }  return null;  }  /** * 执行命令 * * @param command */  private void executeCommand(String command){  Process process = null;  try{  process = Runtime.getRuntime().exec(command);  System.out.println("exec command start: " + command);  process.waitFor();  BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));  String line = bufferedReader.readLine();  if (line != null){  System.out.println(line);  }  System.out.println("exec command end: " + command);  }  catch (Exception e){  e.printStackTrace();  }  finally{  if (process != null){  process.destroy();  }  }  }  /** * ADB获取安卓截屏 */  public void executeADBCaptureCommands(){  for (String command : ADB_SCREEN_CAPTURE_CMDS)  {  executeCommand(command);  }  }  /** * 跳一下 * * @param distance */  public void doJump(double distance){  System.out.println("distance: " + distance);  //计算按压时间,最小200毫秒  int pressTime = (int) Math.max(distance * pressTimeCoefficient, 200);  System.out.println("pressTime: " + pressTime);  //执行按压操作  String command = String.format("adb shell input swipe %s %s %s %s %s", swipeX, swipeY, swipeX, swipeY,  pressTime);  System.out.println(command);  executeCommand(command);  System.out.println();System.out.println();}  /** * 再来一局 */  private void replayGame(){  String command = String.format("adb shell input tap %s %s", swipeX, swipeY);  //adb shell模拟点击事件 inputexecuteCommand(command);  }  /** * 检查是否需要重新开局 */  public void checkDoReplay(){  if (imageLength[0] > 0 && imageLength[0] == imageLength[1] && imageLength[1] == imageLength[2]  && imageLength[2] == imageLength[3] && imageLength[3] == imageLength[4]){  //此时表示已经连续5次图片大小一样了,可知当前屏幕处于再来一局  Arrays.fill(imageLength, 0);  //模拟点击再来一局按钮重新开局  replayGame();  }  }  /** * 获取指定坐标的RGB值 * * @param bufferedImage * @param x * @param y */  private void processRGBInfo(BufferedImage bufferedImage, int x, int y){  this.rgbInfo.reset();  int pixel = bufferedImage.getRGB(x, y);  //转换为RGB数字    this.rgbInfo.setRValue((pixel & 0xff0000) >> 16);  this.rgbInfo.setGValue((pixel & 0xff00) >> 8);  this.rgbInfo.setBValue((pixel & 0xff));  }  /**************************  RGBInfo  ****************************/class RGBInfo{  private int RValue;  private int GValue;  private int BValue;  public int getRValue(){  return RValue;  }  public void setRValue(int rValue){ RValue = rValue;  }  public int getGValue(){  return GValue;  }  public void setGValue(int gValue){  GValue = gValue;  }  public int getBValue(){  return BValue;  }  public void setBValue(int bValue){  BValue = bValue;  }  public void reset(){  this.RValue = 0;  this.GValue = 0;  this.BValue = 0;  }  }
}  
<script src="https://cdn.jsdelivr.net/npm/jquery/dist/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css"/>
<script src="https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget/autoload.js"></script>

跳一跳辅助工具的原理分析,和Java实现。(其实没那么复杂)相关推荐

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

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

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

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

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

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

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

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

  5. python辅助_Python-第一个微信小项目——微信跳一跳辅助工具

    思路 核心:每次落稳之后截图,根据截图算出棋子的坐标和下一个块顶面的中点坐标,根据两个点的距离乘以一个时间系数获得长按的时间 识别棋子:靠棋子的颜色来识别位置,通过截图发现最下面一行大概是一条直线,就 ...

  6. 一个简单的微信跳一跳辅助工具(android)

    前两天手机微信升级到了最新版,多了个跳一跳的游戏,无聊玩了几把,奈何手残,最高只玩到70多分,就想着能不能搞个工具辅助下,于是有了下边的工具: 工具的简单原理如下: 根据前后两个方块的距离计算出一个按 ...

  7. 基于Node.js的微信跳一跳辅助工具

    项目地址:https://github.com/sbfkcel/WechatJumpGameHelper 这是一个需要手动来玩的辅脚本,也是最为保险,官方无法禁封的辅助工具: 支持Mac OS.win ...

  8. 微信跳一跳高分系列四:一个 JAVA 版开源的微信跳一跳辅助工具

    基于前三篇文章,我们一起来制作一个自动化工具,解放劳动力,通过机器自动完成跳一跳 wechat-jump-helper 一款JAVA版开源的微信跳一跳小程序辅助工具 传送门一:wechat-jump- ...

  9. 基于VS+Opencv2.4.10的微信跳一跳辅助工具

    说明:最近微信的跳一跳小程序可谓火了一把,不是因为它本身多好玩,而是有大部分的程序员们加入其中,利用各种领域方法,实现了微信跳一跳的外挂,分数轻松上千或上万.之前也看了基于Python开源的代码,Gi ...

最新文章

  1. tdk怎么设置_不知道怎么分析对手网站?看这里!
  2. html圆形修饰,HTML修饰效果集锦(演示与代码)
  3. Python+opencv 机器视觉 - 基于霍夫圈变换算法检测图像中的圆形实例演示
  4. VC++打开、保存文件对话框和浏览文件夹对话框
  5. SQL Server 2008 BIDS组件的安装
  6. Java 8 新特性:扩展注解(类型注解和重复注解)
  7. java线程“生产/消费”模型2
  8. [css] css中的url()要不要加引号?说说你的理解
  9. 【Pytorch神经网络理论篇】 20 神经网络中的注意力机制
  10. php api查询开发,PHP开发API接口(注册、登录、查询用户信息)的实例代码
  11. Servlet 介绍
  12. JDK成年了,JDK18版本发布,走进JDK18新特性
  13. 5v继电器模块实物接线_继电器实物接线图
  14. 将uiimageview设置成纯圆形
  15. 一张图片切割成九宫格,微信朋友圈发布
  16. 常见的计算机网络联网设备有哪些,常见的网络设备有哪些
  17. HBA-蜜獾算法(Honey Badger Algorithm,HBA)(算法源码可复制)
  18. STM32 Keil快速新建工程
  19. 鸿蒙音波萨顶顶,萨顶顶卸妆堪比整容,“神婆”变女神,网友:早就该这样!...
  20. 强大的图像查看器:EdgeView mac中文

热门文章

  1. windows系统,使用命令行启动MySQL服务失败,报错:服务名无效。
  2. 市场聚焦丨微信人工智能小程序,销售界的又一个风口?
  3. QT学习笔记:简单的串口调试助手--实现 字符与十六进制发送接收
  4. 2020中国高校计算机大赛·华为云大数据挑战赛热身赛--EDA
  5. 【Vue+Java】前后端联动生成下载二维码
  6. 利用java多态实现植物大战僵_植物大战僵尸自动收集阳光金币
  7. Echarts中的 emphasis
  8. java futuretask 状态_java并发编程之FutureTask
  9. educoder机器学习 --- 多分类学习
  10. Android判断应用是否在前台或后台