需要:电脑 java运行环境 adb驱动 微信跳一跳
1920x1080分辨率测试的 其他分辨率需要修改部分参数
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;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class JumpJumpHelper extends Application
{
JumpJumpHelper jumpjumpHelper;
private static final String ADB_Path = "F:/Android/sdk/platform-tools/";
private static final String IMAGE_NAME = "current.png";
private static final String STORE_DIR = System.getProperty("user.dir");
private final RGBInfo rgbInfo = new RGBInfo();
private final String[] ADB_SCREEN_CAPTURE_CMDS =
{ ADB_Path+"adb shell screencap -p /sdcard/" + IMAGE_NAME,ADB_Path+"adb pull /sdcard/current.png " + STORE_DIR };
//截屏中游戏分数显示区域最下方的Y坐标,300是 1920x1080的值,根据实际情况修改
private final int gameScoreBottomY = 300;
//按压的时间系数,可根据具体情况适当调节
private final double pressTimeCoefficient = 1.40;
/**
* 获取跳棋以及下一块跳板的中心坐标
*
* @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[] result = new int[2];
//从截屏从上往下逐行遍历像素点,以棋子颜色作为位置识别的依据,最终取出棋子颜色最低行所有像素点的平均值,即计算出棋子所在的坐标
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 == 54 && gValue == 60 && bValue == 102)
{
result[0] = x;
result[1] = y;
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)
{
System.out.println(command);
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_Path+"adb shell input swipe %s %s %s %s %s", 0, 0, 0, 0,
pressTime);
System.out.println(command);
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));
}
/**
* 获取指定坐标的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));
}
private void mymain(ImageView imageView){
try
{
File storeDir = new File(STORE_DIR);
if (!storeDir.exists()) {
boolean flag = storeDir.mkdir();
if (!flag) {
System.err.println("创建图片存储目录失败");
return;
}
}
jumpjumpHelper = new JumpJumpHelper();
for (;;)
{
//执行ADB命令,获取安卓截屏
jumpjumpHelper.executeADBCaptureCommands();
File currentImage = new File(STORE_DIR, IMAGE_NAME);
if (!currentImage.exists())
{
System.out.println("图片不存在");
continue;
}else{
imageView.setImage(new Image("file:"+new File(STORE_DIR,IMAGE_NAME).getAbsolutePath()));
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(final String[] args)
{
launch(args);
}
private void tiaoyitiao(MouseEvent event) throws Exception{
//获取跳棋和底板的中心坐标
File currentImage = new File(STORE_DIR, IMAGE_NAME);
int[] result = jumpjumpHelper.getHalmaAndBoardXYValue(currentImage);
int halmaX = result[0];
int halmaY = result[1];
double jumpDistance = jumpjumpHelper.computeJumpDistance(halmaX, halmaY, (int)event.getX(), (int)event.getY());
jumpjumpHelper.doJump(jumpDistance);
}
@Override
public void start(final Stage stage) throws Exception {
// TODO Auto-generated method stub
stage.setTitle("跳一跳外挂(切糕王6号)");
stage.getIcons().add(new Image("files/carrot.png"));
Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
// stage.setX(primaryScreenBounds.getMinX());
// stage.setY(primaryScreenBounds.getMinY());
stage.setWidth(primaryScreenBounds.getWidth());
stage.setHeight(primaryScreenBounds.getHeight());
stage.setWidth(1080);
stage.setHeight(1920);
stage.setResizable(false); //�����ڴ�С�̶�
//stage.setAlwaysOnTop(true);//ʼ����ʾ����������֮��
//stage.setFullScreen(true);//ȫ����ʾ��Esc�˳�
//stage.setIconified(true);//��С�����������ɼ�ͼ��
//stage.initStyle(DECORATED);
stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
public void handle(WindowEvent event) {
// System.out.print("���ڹر���");
}
});
System.out.println(new File(STORE_DIR,IMAGE_NAME).getAbsolutePath());
final ImageView imageView = new ImageView();
imageView.setImage(new Image("file:"+new File(STORE_DIR,IMAGE_NAME).getAbsolutePath()));
VBox border = new VBox();
border.getChildren().addAll(imageView);
final Scene scene = new Scene(border, primaryScreenBounds.getWidth(), primaryScreenBounds.getHeight());
scene.setOnMouseClicked(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
// TODO Auto-generated method stub
try {
tiaoyitiao(event);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
stage.setScene(scene);
stage.show();
new Thread(new Runnable() {
public void run() {
// TODO Auto-generated method stub
mymain(imageView);
}
}).start();
}
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;
}
}
}