微信跳一跳辅助Java代码实现
作者:忆虎思甜 发布时间:2022-03-31 19:12:03
标签:Java,微信,跳一跳
微信跳一跳辅助的Java具体实现代码,供大家参考,具体内容如下
1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python环境各种模块缺失,报错不停,于是乎,使用Java重新实现了一下。
2.环境配置及相关说明:
1)、Windows系统,本人win10
2)、AVA环境安装,JDK7以上即可
3)、安卓手机一部、数据线一条
4)、电脑安装ADB驱动,连接安卓手机,同时打开USB调试模式
5)、打开微信小程序的跳一跳游戏,JAVA程序跑起来,具体代码往下看
6)、本人所用为魅蓝note2安卓手机,屏幕 分辨率1920x1080,不同型号的手机,可能需要调整相关参数,具体看代码注释
7)、增加了刷分失败后游戏自动重新开局功能
8)、娱乐而已,不要较真,据说微信官方已经关注,分数太高可能会被清零,哈哈
3、废话不多说,上代码:
package com.yihusitian.gamehelper;
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;
/**
* 参考知乎
*
* @link <a href="https://zhuanlan.zhihu.com/p/32452473" rel="external nofollow" rel="external nofollow" target="_blank">https://zhuanlan.zhihu.com/p/32452473</a>
*
* 跳一跳辅助
*
* @author LeeHo
*/
public class JumpJumpHelper
{
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();
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 = 300;
//按压的时间系数,可根据具体情况适当调节
private final double pressTimeCoefficient = 1.35;
//按压的起始点坐标,也是再来一局的起始点坐标
private final int swipeX = 550;
private final int swipeY = 1580;
//二分之一的棋子底座高度
private final int halfBaseBoardHeight = 20;
//棋子的宽度,从截屏中量取,自行调节
private final int halmaBodyWidth = 74;
//游戏截屏里的两个跳板的中点坐标,主要用来计算角度,可依据实际的截屏计算,计算XY的比例
private final int boardX1 = 813;
private final int boardY1 = 1122;
private final int boardX2 = 310;
private final int boardY2 = 813;
/**
* 获取跳棋以及下一块跳板的中心坐标
*
* @return
* @author LeeHo
* @throws IOException
* @update 2017年12月31日 下午12:18:22
*/
private 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 halmaYMax = 0;
int boardX = 0;
int boardY = 0;
//从截屏从上往下逐行遍历像素点,以棋子颜色作为位置识别的依据,最终取出棋子颜色最低行所有像素点的平均值,即计算出棋子所在的坐标
for (int y = gameScoreBottomY; y < height; y++)
{
for (int x = 0; x < width; x++)
{
processRGBInfo(bufferedImage, x, y);
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++;
//棋子底行的Y坐标值
halmaYMax = y > halmaYMax ? y : halmaYMax;
}
}
}
if (halmaXSum != 0 && halmaXCount != 0)
{
//棋子底行的X坐标值
int halmaX = halmaXSum / halmaXCount;
//上移棋子底盘高度的一半
int halmaY = halmaYMax - halfBaseBoardHeight;
//从gameScoreBottomY开始
for (int y = gameScoreBottomY; y < height; y++)
{
processRGBInfo(bufferedImage, 0, y);
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();
//处理棋子头部比下一个跳板还高的情况
if (Math.abs(x - halmaX) < halmaBodyWidth)
{
continue;
}
//从上往下逐行扫描至下一个跳板的顶点位置,下个跳板可能为圆形,也可能为方框,取多个点,求平均值
if ((Math.abs(pixelR - lastPixelR) + Math.abs(pixelG - lastPixelG) + Math.abs(pixelB - lastPixelB)) > 10)
{
boardXSum += x;
boardXCount++;
}
}
if (boardXSum > 0)
{
boardX = boardXSum / boardXCount;
}
}
//按实际的角度来算,找到接近下一个 board 中心的坐标
boardY = (int) (halmaY - Math.abs(boardX - halmaX) * Math.abs(boardY1 - boardY2)
/ Math.abs(boardX1 - boardX2));
if (boardX > 0 && boardY > 0)
{
int[] result = new int[4];
//棋子的X坐标
result[0] = halmaX;
//棋子的Y坐标
result[1] = halmaY;
//下一块跳板的X坐标
result[2] = boardX;
//下一块跳板的Y坐标
result[3] = boardY;
return result;
}
}
return null;
}
/**
* 执行命令
*
* @param command
* @author LeeHo
* @update 2017年12月31日 下午12:13:39
*/
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获取安卓截屏
*
* @author LeeHo
* @update 2017年12月31日 下午12:11:42
*/
private void executeADBCaptureCommands()
{
for (String command : ADB_SCREEN_CAPTURE_CMDS)
{
executeCommand(command);
}
}
/**
* 跳一下
*
* @param distance
* @author LeeHo
* @update 2017年12月31日 下午12:23:19
*/
private 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);
}
/**
* 再来一局
*
* @author LeeHo
* @update 2017年12月31日 下午12:47:06
*/
private void replayGame()
{
String command = String.format("adb shell input tap %s %s", swipeX, swipeY);
executeCommand(command);
}
/**
* 计算跳跃的距离,也即两个点之间的距离
*
* @param halmaX
* @param halmaY
* @param boardX
* @param boardY
* @return
* @author LeeHo
* @update 2017年12月31日 下午12:27:30
*/
private double computeJumpDistance(int halmaX, int halmaY, int boardX, int boardY)
{
return Math.sqrt(Math.pow(Math.abs(boardX - halmaX), 2) + Math.pow(Math.abs(boardY - halmaY), 2));
}
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;
}
}
JumpJumpHelper jumpjumpHelper = new JumpJumpHelper();
//执行次数
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);
if (result == null)
{
System.out.println("The result of method getHalmaAndBoardXYValue is null!");
continue;
}
int halmaX = result[0];
int halmaY = result[1];
int boardX = result[2];
int boardY = result[3];
System.out.println("halmaX: " + halmaX + ", halmaY: " + halmaY + ", boardX: " + boardX + ", boardY: "
+ boardY);
//计算跳跃的距离
double jumpDistance = jumpjumpHelper.computeJumpDistance(halmaX, halmaY, boardX, boardY);
jumpjumpHelper.doJump(jumpDistance);
//每次停留2.5秒
TimeUnit.MILLISECONDS.sleep(2500);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
/**
* 检查是否需要重新开局
*
* @author LeeHo
* @update 2017年12月31日 下午1:39:18
*/
private 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
* @author LeeHo
* @update 2017年12月31日 下午12:12:43
*/
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));
}
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;
}
}
}
更多内容大家可以参考专题《微信跳一跳》进行学习。
来源:http://blog.csdn.net/lihushiwoa/article/details/78942322
0
投稿
猜你喜欢
- 本文实例总结了Android开发中Toast显示消息的方法。分享给大家供大家参考,具体如下:Android中提供一种简单的Toast消息提示
- 前言:什么是多数据源?最常见的单一应用中最多涉及到一个数据库,即是一个数据源(Datasource)。那么顾名思义,多数据源就是在一个单一应
- 前言在我们日常的开发中,很多时候,定时任务都不是写死的,而是写到数据库中,从而实现定时任务的动态配置,下面就通过一个简单的示例,来实现这个功
- 在Web应用系统开发中,文件上传和下载功能是非常常用的功能,今天来讲一下JavaWeb中的文件上传和下载功能的实现。文件上传概述1、文件上传
- 官方文档 8.0Spring为不同缓存做了一层抽象,这里通过阅读文档以及源码会对使用以及原理做一些学习笔记。1.简介
- 本篇使用java自带的MessageDigest实现对文本的md5加密算法,具体代码如下: /** *@Description
- 以前使用spring的使用要注入property要配置PropertyPlaceholder的bean对象。在springboot除&nbs
- 承蒙各位厚爱,我们一起每天进步一点点!(鼠标选中空白处查看答案)1、现有如下代码段:x = 2;while(x<n/2){x = 2*
- 在 String 中提供了两个截取字符串的方法,一个是从指定位置截取到字符串结尾,另一个是截取指定范围的内容。下面对这两种方法分别进行介绍。
- Eclipse的Servers视图中无法添加Tomcat6/Tomcat7的方法引言: 在基于Eclipse的开发过程中,出现了无法在Ecl
- 本文实例讲述了Java循环队列原理与用法。分享给大家供大家参考,具体如下:在正式进行循环队列学习之前,我们先来看看在顺序队列中删除队首元素出
- 如果不知道,类的静态变量存储在那? 方法的局部变量存储在那? 赶快收藏Java内存区域主要可以分为共享内存,堆、方法区和线程私有内存,虚拟机
- 前言在我们做后端服务Dao层开发,特别是大数据批量插入的时候,这时候普通的ORM框架(Mybatis、hibernate、JPA)就无法满足
- 使用flatMap列出子目录前面已经看到如何列出指定目录下的文件了。我们再来看下如何遍历指定目录的直接子目录(深度为1),先实现一个简单的版
- 需要用到 java 写一个 ftp 的工具,因为只有一点点 java 基础,但是由于好几年不用,几乎算是不会了,只好一点点来搞,还好能捡起来
- Springboot 在普通类型注入Service或mapper最近遇到一个难题(大佬可能感觉这太简单了把),对于我这样的小白来说,确实有些
- 这是一个高级Java面试系列题中的第一部分。这一部分论述了可变参数,断言,垃圾回收,初始化器,令牌化,日期,日历等等Java核心问题。接下来
- Spring Security中的内置过滤器顺序是怎么维护的?我想很多开发者都对这个问题感兴趣。本篇我和大家一起探讨下这个问题。HttpSe
- 前文本章是关于Java流程控制语句的最全汇总,本篇为汇总中篇。流程是人们生活中不可或缺的一部分,它表示人们每天都在按照一定的流程做事。比如出
- 简介MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)