微信跳一跳辅助-Java版

作者: 53b3f4658edc | 来源:发表于2018-01-04 20:07 被阅读152次

    概述

    最近微信小程序-跳一跳风靡朋友圈,大家靠人去跳一般止步在2、300次,我们可以使用ADB+Java来完成这个微信跳一跳的辅助。

    步骤:

    1.电脑安装ADB驱动。
    2.准备安卓手机一台(模拟器也可以)。
    3.Java开发环境(JDK+Eclipse)。
    4.查询自己的安卓手机(模拟器)的相关参数,主要是屏幕分辨率,在代码中进行相关更改。
    5.打开微信跳一跳游戏。
    6.使用abd连接手机。
    7.运行Java程序。

    1.电脑安装ADB驱动(文末有提供)。

    下载adb包后解压到桌面就可以。


    微信公众号:JavaWeb架构师

    2.准备安卓手机或者模拟器

    我用的是模拟器,推荐使用叠蓝

    微信公众号:JavaWeb架构师

    3.Java开发环境搭建

    推荐下面这篇文章认识JDK并配置path环境变量

    4.查询自己的安卓手机(模拟器)的相关参数

    我把模拟器设置成了1920*1080的分辨率。


    微信公众号:JavaWeb架构师

    5.打开微信跳一跳游戏

    微信公众号:JavaWeb架构师

    6.使用abd连接手机

    在刚刚解压后的abd文件夹中有一个cmd.exe文件,双击打开它,并输入下面的命令:

    adb connect 127.0.0.1
    

    如出现以下提示,则连接成功:


    微信公众号:JavaWeb架构师

    7.运行Java程序


    微信公众号:JavaWeb架构师

    其中,对图像中物体的判断,只是使用的rgb,如果有图形识别更佳。

    package top.itcourse.jump;
    
    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;
    
    /** 
    * @author 微信公众号:JavaWeb架构师
    * @version 创建时间:2018年1月1日 下午4:29:24 
    */
      
    
    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    = 2.7;  
      
        //按压的起始点坐标,也是再来一局的起始点坐标  
        private final int           swipeX                  = 550;  
      
        private final int           swipeY                  = 1580;  
      
        //二分之一的棋子底座高度  
        private final int           halfBaseBoardHeight     = 20;  
      
        //棋子的宽度,从截屏中量取,自行调节  
        private final int           halmaBodyWidth          = 70;  
      
        //游戏截屏里的两个跳板的中点坐标,主要用来计算角度,可依据实际的截屏计算,计算XY的比例  
        private final int           boardX1                 = 813;  
      
        private final int           boardY1                 = 1500;  
      
        private final int           boardX2                 = 310;  
      
        private final int           boardY2                 = 813;  
      
        /** 
         * 获取跳棋以及下一块跳板的中心坐标 
         * 
         * @return 
         * @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 > 60 && rValue < 65 && gValue > 50 && gValue < 55 && bValue > 80 && bValue < 90)  
                    {  
                        halmaXSum += x;  
                        halmaXCount++;  
                        //棋子底行的Y坐标值  
                        halmaYMax = y > halmaYMax ? y : halmaYMax;  
                    }  
                }  
            }  
      
            if (halmaXSum != 0 && halmaXCount != 0)  
            {  
                //棋子底行的X坐标值(平均值)
                int halmaX = halmaXSum / halmaXCount;  
                // 上移棋子底盘高度的一半  
                int halmaY = halmaYMax - halfBaseBoardHeight;  
                
                System.out.println("棋子的位置:" + halmaX + "," + halmaY);
               
                // 下一个棋子的位置
                //从gameScoreBottomY开始  
                processRGBInfo(bufferedImage, 0, 0);  
                int lastPixelR = this.rgbInfo.getRValue();  
                int lastPixelG = this.rgbInfo.getGValue();  
                int lastPixelB = this.rgbInfo.getBValue();  
                for (int y = gameScoreBottomY; y < height; y++)  
                {  
                    
                    //只要计算出来的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)) > 5)  
                        {  
                            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 
         * @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获取安卓截屏 
         *  
         * @update 2017年12月31日 下午12:11:42 
         */  
        private void executeADBCaptureCommands()  
        {  
            for (String command : ADB_SCREEN_CAPTURE_CMDS)  
            {  
                executeCommand(command);  
            }  
        }  
      
        /** 
         * 跳一下 
         * 
         * @param distance 
         * @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);  
        }  
      
        /** 
         * 再来一局 
         *  
         * @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 
         * @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();  
            }  
        }  
      
        /** 
         * 检查是否需要重新开局 
         *  
         * @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 
         * @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;  
            }  
        }  
    }  
    
    微信公众号:JavaWeb架构师

    其它

    • adb、Java程序下载
    关注下方公众号,回复:java_jump.code
    
    完整教程PDF版本下载

    相关文章

      网友评论

        本文标题:微信跳一跳辅助-Java版

        本文链接:https://www.haomeiwen.com/subject/lqldnxtx.html