Java版跳一跳
public static void main(String[] args) throws Exception { // 删除临时文件 File f = new File(filePath); if (!f.exists()) { f.mkdir(); } else { for (File ff : f.listFiles()) { ff.delete(); } } // 记录日志 PrintStream print = new PrintStream(new FileOutputStream(new File(filePath + "log.txt"), false), true, "UTF-8"); System.setOut(print); JTextArea textArea = initJFrame(); int i = 0; while (true) { if (!jump) { Thread.sleep(5000); continue; } i++; // 100次清空文本域一次 if (i % 100 == 0) { textArea.setText(""); } String fileName = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date()) + "_" + i + ".png"; File file = new File(filePath + fileName); System.out.println(fileName + "--------------------------------获取图片"); textArea.append(fileName.substring(11, fileName.length() - 4) + "---------------获取图片\r\n"); textArea.setCaretPosition(textArea.getDocument().getLength()); // 更新图片 保留五位数不足补0 在文件夹排序用 pullImg(file); // 加载图片 BufferedImage image = getImage(file); if (image == null) { throw new RuntimeException("图片不能为空!!!"); } // 重新设置全局宽高 new Jump_Jump(image.getWidth(), image.getHeight()); // 获取起始点 int[] startPoint = findStartPoint(image); // 判断小人起始点不为空,并且不是重新开始按键(有的人头像是小人一样的颜色) -16726153为开始按钮上的绿色 if (startPoint != null && image.getRGB(GAMEOVER_X2, GAMEOVER_Y2) != -16726153) { // 获取背景色上下值 int[] backGround = getBackGround(image); // 获取顶点坐标 int[] topPoint = getTopPoint(image, startPoint, backGround); // 获取白点为目标点 // int[] endPoint = getWhitePoint(image, topPoint); // 如果不是白点则继续找最大最小值 // if (endPoint == null) { // 获取XY最大最小值坐标 int[] maxMinXY = getMaxMinXY(image, startPoint, topPoint); // 获取目标坐标 int[] endPoint = findEndPoint(image, maxMinXY); // } else { // System.out.println("'\t\t\t------------找到白点!!!"); // } // 小人到目标坐标距离 勾股定理 double distance = (Math.sqrt(Math.pow((endPoint[0] - startPoint[0]), 2) + Math.pow((endPoint[1] - startPoint[1]), 2))); // 计算按压时间 double pm = PM + ((DISTANCE_CRITICAL - distance) / 8000); System.out.println("顶点 [" + endPoint[2] + "," + endPoint[3] + "]\t左点 [" + endPoint[4] + "," + endPoint[5] + "]\t右点 [" + endPoint[6] + "," + endPoint[7] + "]"); System.out.println("起点 [" + startPoint[0] + "," + startPoint[1] + "]" + "\t终点 [" + endPoint[0] + "," + endPoint[1] + "]"); System.out.println("距离: " + (int) distance + "\t系数: " + String.format("%.3f", pm)); if (jump) { textArea.append("距离: " + (int) distance + "\t系数: " + String.format("%.3f", pm) + "\r\n"); textArea.setCaretPosition(textArea.getDocument().getLength() - 1); // 按压开始跳 最小300毫秒 press(Math.max((int) (distance * pm), 0)); } // 写出图片加入跳的信息 drawImage(image, file, startPoint, endPoint, (int) distance + "*" + String.format("%.3f", pm) + "=" + (int) (distance * pm)); // 获取图片前睡几秒等小人落地,连续命中白点,放出去的圈圈影响顶点寻找 Thread.sleep(200 + Math.max((int) distance, 600)); } else { // 找不到小人起始点,就是重新开始 textArea.append("无法获小人取起始点!!!\r\n"); textArea.setCaretPosition(textArea.getDocument().getLength()); // 判断开始按钮 if (image.getRGB(GAMEOVER_X2, GAMEOVER_Y2) == -16726153) { // 重新按压 execute(String.format("adb shell input tap %d %d", GAMEOVER_X + new Random().nextInt(100), GAMEOVER_Y + new Random().nextInt(50))); } // 歇一会,等到小人落地 Thread.sleep(5000); // execute("adb shell input keyevent 4"); // execute("adb shell input keyevent 4"); // execute("adb shell input keyevent 26"); continue; } } } /**初始化窗口*/ public static JTextArea initJFrame() { JFrame f = new JFrame("跳一跳");// 实例化一个窗体框架 Container c = f.getContentPane();// 获取窗口容器 c.setLayout(new FlowLayout());// 设置布局模式 JPanel p1 = new JPanel(new GridLayout(1, 2, 10, 0));// 开始暂停按钮面板 JPanel p2 = new JPanel(new GridLayout(1, 1, 0, 0));// 文本域面板 JPanel p3 = new JPanel(new GridLayout(2, 1, 0, 2));// 距离系数面板 JButton b1 = new JButton("调整系数");// 调整系数按钮 final JButton b2 = new JButton("开 始");// 开始暂停按钮 final JTextField t1 = new JTextField(10);// 文本框 final JTextArea t2 = new JTextArea("点击开始......\r\n");// 文本域 // 设置文本框 t1.setText(PM + "");// 初始化文本框 t1.setFont(new Font("微软雅黑", Font.PLAIN, 20));// 设置字体 t1.setBackground(new Color(222, 222, 222));// 设置背景色 t1.setCaretPosition(t1.getText().length());// 设置光标位置 t1.setForeground(Color.BLUE);// 设置文本颜色 t1.setCaretColor(Color.RED);// 设置光标颜色 t1.setSelectionColor(Color.CYAN);// 设置文本选中颜色 // 设置文本域 t2.setLineWrap(true);// 超出范围自动换行显示 t2.setWrapStyleWord(true); t2.setEditable(false);// 设置不可编辑 t2.setTabSize(4);// 设置Tab长度 t2.setFont(new Font("微软雅黑", Font.PLAIN, 14));// 设置字体 t2.setBackground(Color.LIGHT_GRAY);// 设置背景颜色 t2.setForeground(Color.RED);// 设置字体颜色 t2.setMargin(new Insets(5, 5, 15, 5));// 设置边距 // 设置按钮 b2.setFocusable(false);// 按钮文字外面的框框 b2.setFont(new Font("微软雅黑", Font.BOLD, 34));// 设置按钮字体 b1.setFocusable(false); b1.setFont(new Font("微软雅黑", Font.BOLD, 14)); // 点击事件 ActionListener action = new ActionListener() { public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); // 开始功能 if ("开 始".equals(command) || "Enter".equals(command)) { b2.setText("暂 停"); jump = true; t2.append("开 始......\r\n"); // 暂停功能 } else if ("暂 停".equals(command) || "Esc".equals(command)) { b2.setText("开 始"); jump = false; t2.append("暂 停......\r\n"); // 调整系数功能 } else if ("调整系数".equals(command)) { String text = t1.getText(); // 判断文本框输入参数的类型 boolean matches = Pattern.compile("^[-\\+]?[.\\d]*$").matcher(text).matches(); if (matches) { PM = Double.parseDouble(text); t2.append("距离系数调整为: " + PM + "\r\n"); } else { t2.append(text + " 不是数字,请输入数字!!!\r\n"); } } t2.setCaretPosition(t2.getDocument().getLength()); } }; // 开始暂停按钮点击事件 b2.addActionListener(action); b2.setMnemonic(KeyEvent.VK_ENTER); b2.registerKeyboardAction(action, "Enter", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); b1.registerKeyboardAction(action, "Esc", KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); // 距离系数按钮点击事件 b1.addActionListener(action); // 设置面板 p1.setPreferredSize(new Dimension(290, 100));// 面板大小 p2.setPreferredSize(new Dimension(290, 160)); p1.setBorder(BorderFactory.createTitledBorder("功能"));// 包裹面板的框框 p2.setBorder(BorderFactory.createTitledBorder("输出")); p3.setBorder(BorderFactory.createTitledBorder("距离系数")); p1.add(p3);// 添加调整距离系数面板 p1.add(b2);// 添加开始暂停按钮 p2.add(new JScrollPane(t2));// 添加文本域且文本域滚动 p3.add(t1);// 添加距离系数文本框 p3.add(b1);// 添加距离系数按钮 // 设置窗口 c.add(p1);// 添加功能面板 c.add(p2);// 添加输出面板 f.setFocusable(true);// 设置获取焦点 f.setSize(300, 300); // 设置大小 f.setLocation(1000, 20); // 设置窗体位置 f.setVisible(true); // 设置是否可见 f.setResizable(false);// 不能改变窗体大小 f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setAlwaysOnTop(true);// 设置窗口是否总在最上面 f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0);// 当点击按钮时退出程序 } }); f.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { } }); return t2; } /**修正距离转时间参数*/ public static double getPM(double distance) { // 正常情况下, 远的跳的远 近的跳的近 double pm = 0d; if (pm == 1000) { } else if (distance >= 660) { return 1.52d - distance / 10000; } else if (distance >= 600 && distance < 660) { return 1.53d - distance / 10000; } else if (distance >= 550 && distance < 600) { return 1.54d - distance / 10000; } else if (distance >= 500 && distance < 550) { pm = 9;// 跳近了 改小 [1-100] } else if (distance >= 450 && distance < 500) { pm = 11; } else if (distance >= 300 && distance < 450) { pm = 13; } else if (distance >= 250 && distance < 300) { pm = 15; } else if (distance >= 200 && distance < 250) { pm = 13; } else if (distance >= 150 && distance < 200) { pm = 11; } else if (distance < 150) { pm = 9; } return ((560d - distance) / (pm * 100)) + 1.42; } /** 找小人 开始点 判断小人颜色*/ public static int[] findStartPoint(BufferedImage image) { int maxX = -1; int minX = W; int maxY = -1; int minY = H; for (int x = 0; x < W; x++) { // 小人坐标都是在高度1/4距离到高度4/3距离内 for (int y = H / 4; y < H * 3 / 4; y++) { // 判断小人当前坐标是否在小人颜色误差范围 小人颜色为 54 60 100 误差范围10 if (isRange(image, x, y, 54, 60, 100, 10)) { maxX = Math.max(maxX, x); minX = Math.min(minX, x); maxY = Math.max(maxY, y); minY = Math.min(minY, y); } } } // 取小人颜色一样最大最小X坐标求平均值,实测要减去3像素 小人底座最下方到方块中心 实测要减去18像素 int[] res = { (maxX + minX) / 2 - 3, maxY - 18 }; if (res[0] <= 0 || res[1] <= 0) { return null; } return res; } /** 获取屏幕背景色 Y轴渐变色,取上下值*/ public static int[] getBackGround(BufferedImage image) { // 背景色取最下方 左 中 右 避免遮挡 // 背景色左方 int leftRgb = image.getRGB(0, H - 1); // 背景色右方 int rightRgb = image.getRGB(W - 1, H - 1); // 背景色左方4/1 int leftRgb2 = image.getRGB((int) (W / 4), H - 1); // 背景色右方4/1 int rightRgb2 = image.getRGB((int) (W * 3 / 4), H - 1); // 背景色中间 int centerRgb = image.getRGB((int) (W / 2), H - 1); // 默认取左边 int rgb = leftRgb; // 左右不相等,判定取左还是右 if (leftRgb != rightRgb) { // 如果右边和右边四分之一相等,并且左边和左边四分之一不相等,或者右边等于一半时的值,则取右边 if ((leftRgb != leftRgb2 && rightRgb == rightRgb2) || rightRgb == centerRgb) { rgb = rightRgb; } } // 背景色最上方,下方颜色 int[] topRGB = getMyRGB(image, 0, BACKGROUND_MIN_X); Color downRGB = new Color(rgb); return new int[] { topRGB[0], topRGB[1], topRGB[2], downRGB.getRed(), downRGB.getGreen(), downRGB.getBlue() }; } /**获取顶点 */ public static int[] getTopPoint(BufferedImage image, int[] startPoint, int[] backBroundRGB) { // 找顶点,记录顶点颜色 从图片1/4位置开始,到小人Y轴结束 for (int y = H / 4; y < startPoint[1]; y++) { for (int x = 100; x < W - 100; x++) { boolean isBody = false; // 过滤小人,防止小人比目标高 小人高度208(底座18),宽度75 if (Math.abs(startPoint[0] - x) < BODY_X / 2 + 5 && Math.abs(startPoint[1] - y) < BODY_Y - 18 + 5) { isBody = true; } // 如果不在背景色范围,则是顶点,找到顶点则停止 if (!isBackBround(image, x, y, backBroundRGB, 5) && !isBody) { // 顶点向下找30个点如果有背景色,则跳出继续找顶点,抗干扰音符颜色一样最大Y30 boolean b = true; for (int i = 0; i < SQUARE_MIN_Y; i++) { if (isBackBround(image, x, y + i, backBroundRGB, 5)) { b = false; break; } } if (!b) { continue; } return new int[] { x, y }; } } } return null; } /**获取XY最大最小值*/ public static int[] getMaxMinXY(BufferedImage image, int[] startPoint, int[] topPoint) { 此处省略.................. 详情请到CSDN下载 http://download.csdn.net/download/lzlrl/10242212 return new int[] { (maxX + minX) / 2, (maxY + minY) / 2, topX, topY, minX, minY, maxX, maxY }; } /**找白点 为目标点*/ public static int[] getWhitePoint(BufferedImage image, int[] topPoint) { // 先找白点 , 菱形音乐播放器最宽 for (int i = topPoint[0]; i < topPoint[0] + TOP_WRITE_X; i++) { for (int j = topPoint[1]; j < topPoint[1] + TOP_WRITE_Y; j++) { int[] whitePoint = isWhitePoint(image, i, j); // 判断白点,如果有连续击中的白点,直接返回白点坐标 if (whitePoint != null) { return whitePoint; } } } return null; } /**判断白点 白点Y长度22 X长度38, 只判断Y轴不准确,再加X轴**/ public static int[] isWhitePoint(BufferedImage image, int x, int y) { // 循环Y 向下找20个点的颜色,如果这20个点都是白色,并且这20个点上下不是白色,则为白点 for (int i = y, num = 3, num2 = WRITE_Y + 3; i <= y + WRITE_Y - 2; i++, num++, num2--) { // 判断当前点不上白点则返回 int[] myRGB = getMyRGB(image, x + 2, i); int r = myRGB[0]; int g = myRGB[1]; int b = myRGB[2]; // 白点的颜色RGB为245 判断 Y向下22个点如果有不是白色的直接返回 if (!(r == 245 && g == 245 && b == 245)) { return null; } // 判断白点圆圈上面第3个点是白点则返回 int[] myRGB2 = getMyRGB(image, x + 2, i - num); int r2 = myRGB2[0]; int g2 = myRGB2[1]; int b2 = myRGB2[2]; // 判断白点圆圈下面第3个点是白点则返回 int[] myRGB3 = getMyRGB(image, x + 2, i + num2); int r3 = myRGB3[0]; int g3 = myRGB3[1]; int b3 = myRGB3[2]; // 判断Y轴上这22个点外的第三个点是白色则返回 if ((r2 == 245 && g2 == 245 && b2 == 245) || r3 == 245 && g3 == 245 && b3 == 245) { return null; } } // 有竖条为白色的刚好是22个像素(药瓶), 循环X 向左右找15个点的颜色,如果这15个点都是白色则为白点 for (int i = x - (WRITE_X - 13); i <= x + (WRITE_X - 13); i++) { int[] myRGB = getMyRGB(image, i, y + 10); int r = myRGB[0]; int g = myRGB[1]; int b = myRGB[2]; if (!(r == 245 && g == 245 && b == 245)) { return null; } } // 白点的中心点为 X+2,Y+(22/2) return new int[] { x + 2, y + 11, 0, 0, 0, 0, 0, 0 }; } /** 找终点 */ /** 1.取背景色(很重要,他决定了顶点) 2.找到顶点 (没有顶点,一切免谈) 3.从顶点颜色开始,到背景色结束, 找和顶点颜色一样的最大(顶点往右)最小(顶点往左)坐标 4.计算中心点,最大加最小除以二 5.判断是否找到中心点,如果没找到,则取顶点往下位移50或者20的坐标 */ @SuppressWarnings("unused") public static int[] findEndPoint(BufferedImage image, int[] resXY) { // 顶点 int topX = resXY[2]; int topY = resXY[3]; // 获取XY最大最小值 int minX = resXY[4]; int minY = resXY[5]; int maxX = resXY[6]; int maxY = resXY[7]; // 判断药瓶 药瓶顶点颜色为纯白色 // int[] topRGB = getMyRGB(image, topX, topY); // if (topRGB[0] == 255 && topRGB[0] == topRGB[1] && topRGB[0] == topRGB[2]) { // // 判断药瓶顶点Y正下方加130颜色 如果是这个,则顶点往下加30,101, 135, 164为药瓶下面蓝色 // if (isRange(image, topX, topY + 130, 101, 135, 164, 5)) { // System.out.println("----------找到药瓶!!!"); // return new int[] { topX + 8, topY + 26, 0, 0, 0, 0, 0 , 0 }; // } // } // 终极办法防止未知情况,X最大最小不能超过460不能小于底座80 Y最大最小不能超过290不能小于底座40 if (false) { } else if (minX - topX > SQUARE_MAX_X / 2 + 20) { resXY[0] = topX; resXY[1] = maxY; System.out.println("'\t\t\t------------左X过大(minX - topX)= " + (minX - topX)); } else if (topX - minX < BODY_X / 2 - 18) { resXY[0] = topX; resXY[1] = minY; System.out.println("'\t\t\t------------左X过小(topX - minX)= " + (topX - minX)); } else if (minY - topY > SQUARE_MAX_Y / 2) { resXY[0] = topX; resXY[1] = maxY; System.out.println("'\t\t\t------------左Y过大(minY - topY)= " + (minY - topY)); } else if (minY - topY < SQUARE_MIN_Y / 2 - 4) { resXY[0] = topX; resXY[1] = minY; System.out.println("'\t\t\t------------左Y过小(minY - topY)= " + (minY - topY)); } if (maxX - topX > SQUARE_MAX_X / 2 + 40) { resXY[0] = topX; resXY[1] = minY; System.out.println("'\t\t\t------------右X过大(maxX - topX)=" + (maxX - topX)); } else if (maxX - topX < SQUARE_MIN_Y / 2 - 4) { resXY[0] = topX; resXY[1] = maxY; System.out.println("'\t\t\t------------右X过小(maxX - topX)= " + (maxX - topX)); } else if (maxY - topY > SQUARE_MAX_Y / 2 + 10) { resXY[0] = topX; resXY[1] = minY; System.out.println("'\t\t\t------------右Y过大(maxY - topY)= " + (maxY - topY)); } else if (maxY - topY < BODY_X / 2 - 20) { resXY[0] = topX; resXY[1] = minY; System.out.println("'\t\t\t------------右Y过小(maxY - topY)= " + (maxY - topY)); } return resXY; } /** 发送按压屏幕指令 */ public static void press(int pressTime) throws IOException { Random random = new Random(); int pressX = PRESS_X + random.nextInt(170); int pressY = PRESS_Y + random.nextInt(200); int pressX2 = PRESS_X + random.nextInt(170); int pressY2 = PRESS_Y + random.nextInt(200); execute(String.format("adb shell input swipe %d %d %d %d %d", pressX, pressY, pressX2, pressY2, pressTime)); } /** 发送截图拉取图片指令 */ public static void pullImg(File file) throws IOException, InterruptedException { execute("adb shell /system/bin/screencap -p /sdcard/img.png"); execute("adb pull /sdcard/img.png " + file.getAbsolutePath()); } /** 加载图片 */ public static BufferedImage getImage(File file) { BufferedImage image = null; InputStream in = null; try { in = new FileInputStream(file); image = ImageIO.read(in); } catch (IOException e) { e.printStackTrace(); } finally { try { if (in != null) { in.close(); } } catch (IOException e) { e.printStackTrace(); } } return image; } /** 获取指定坐标的RGB值 */ public static int[] getMyRGB(BufferedImage image, int x, int y) { try { int pixel = image.getRGB(x, y); int r = (pixel & 0xff0000) >> 16; int g = (pixel & 0xff00) >> 8; int b = (pixel & 0xff); return new int[] { r, g, b }; } catch (Exception e) { System.out.println("获取RGB异常!!!" + x + ":" + y); e.printStackTrace(); } return new int[] { 0, 0, 0 }; } /** 获取指定坐标的RGB值是否在范围 t为误差值 */ public static boolean isRange(BufferedImage image, int x, int y, int r, int g, int b, int e) { int[] myRGB = getMyRGB(image, x, y); int r2 = myRGB[0]; int g2 = myRGB[1]; int b2 = myRGB[2]; // System.out.println(x + "," + y + ":" + r2 + "," + g2 + "," + b2); return r2 >= r - e && r2 <= r + e && g2 >= g - e && g2 <= g + e && b2 >= b - e && b2 <= b + e; // return Math.sqrt(Math.pow((r2 - r), 2) + Math.pow((g2 - g), 2) + Math.pow((b2 - b), 2)) > e; } /** 判断是否在背景色范围 t为误差值*/ public static boolean isBackBround(BufferedImage image, int x, int y, int[] rgb, int e) { int r, g, b, r1, g1, b1, r2, g2, b2, minR, maxR, minG, maxG, minB, maxB; // 需要判断的颜色 int[] myRGB = getMyRGB(image, x, y); r = myRGB[0]; g = myRGB[1]; b = myRGB[2]; r1 = rgb[0]; g1 = rgb[1]; b1 = rgb[2]; r2 = rgb[3]; g2 = rgb[4]; b2 = rgb[5]; minR = Math.min(r1, r2) - e; maxR = Math.max(r1, r2) + e; minG = Math.min(g1, g2) - e; maxG = Math.max(g1, g2) + e; minB = Math.min(b1, b2) - e; maxB = Math.max(b1, b2) + e; return r >= minR && r <= maxR && g >= minG && g <= maxG && b >= minB && b <= maxB; } /** 执行ADB命令 */ private static void execute(String command) { Process process = null; try { process = Runtime.getRuntime().exec(command); process.waitFor(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("执行ADB异常!!! " + command); } finally { if (process != null) { process.destroy(); } } } /** 给图片在图上标注起点终点 */ public static void drawImage(BufferedImage image, File file, int[] startPoint, int[] endPoint, String message) { Graphics2D g = image.createGraphics(); g.setColor(new Color(255, 0, 0));// 255, 128, 255 g.setBackground(Color.white); g.setFont(new Font("微软雅黑", Font.PLAIN, 40)); // 字体 字型 字号 g.drawLine(startPoint[0], startPoint[1], endPoint[0], endPoint[1]); g.drawString(message, (startPoint[0] + endPoint[0]) / 2, (startPoint[1] + (startPoint[1] + endPoint[1]) / 2) / 2); g.drawString("+", startPoint[0] - 15, startPoint[1] + 13); g.drawString("+", endPoint[0] - 15, endPoint[1] + 13); if (endPoint[6] > 0) { g.drawString(".", endPoint[2] - 4, endPoint[3] + 3); g.drawString(".", endPoint[4] - 4, endPoint[5] + 3); g.drawString(".", endPoint[6] - 4, endPoint[7] + 3); } g.dispose(); FileOutputStream out = null; try { out = new FileOutputStream(file.getAbsolutePath()); ImageIO.write(image, "png", out); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException e) { e.printStackTrace(); } } } }
相关推荐
-
Apache POI 工具类 [ PoiUtil ] java
2019-1-8
-
QRCodeGenerator.java java
2019-1-8
-
jvm 线程信息诊断、stack 信息打印 java
2019-1-13
-
springBoot版OSS上传功能【可检查魔数】 java
2019-1-7
-
二维码的生成和读取 java
2019-1-7
-
删除 java代码中所有的注释 java
2019-1-7
-
SSM整合所需jar java
2019-1-13
-
Java获取当前系统信息 java
2019-1-12
-
java执行bat代码 java
2019-1-8
-
Spring 集群定时任务的redis实现 java
2019-1-7