• 微信跳一跳辅助JAVA 自动模拟点击


    工具:ADB

    原理:

    1. 开始游戏后,使用ADB工具让手机截屏发送到电脑
    2. 分析图像中小人与目标中心点间的距离,根据一定比例计算出需要触屏的时间
    3. 使用ADB进行模拟点击(触屏)相应的时间,完成精准跳跃

    程序代码:

      1 import java.awt.EventQueue;
      2 import java.awt.Graphics;
      3 
      4 import javax.swing.JFrame;
      5 import javax.swing.JLabel;
      6 import java.awt.BorderLayout;
      7 import java.awt.Color;
      8 
      9 import javax.imageio.ImageIO;
     10 import javax.swing.ImageIcon;
     11 import java.awt.event.MouseAdapter;
     12 import java.awt.event.MouseEvent;
     13 import java.awt.image.BufferedImage;
     14 import java.io.File;
     15 import java.io.IOException;
     16 import java.math.BigDecimal;
     17 
     18 public class Skip {
     19     /*
     20      * 以下参数根据手机配置自行调整:
     21      */
     22     private final int time = 2800;        //执行跳跃间隔时间(单位:ms)
     23     private final double scale = 2.04;    //用于计算按下屏幕时间的比例,触屏时间=距离*scale
     24     
     25     private JFrame frame;                //窗体
     26     private JLabel lblNewLabel;            //用于显示图片的Label
     27     private BufferedImage image;        //手机截屏
     28     private int skipTime = 0;            //跳跃次数
     29     /**
     30      * Launch the application.
     31      */
     32     public static void main(String[] args) {
     33         EventQueue.invokeLater(new Runnable() {
     34             public void run() {
     35                 try {
     36                     Skip window = new Skip();        //跳一跳类实例
     37                     window.frame.setVisible(true);    //设置窗体可见
     38                 } catch (Exception e) {
     39                     e.printStackTrace();
     40                 }
     41             }
     42         });
     43     }
     44 
     45     /**
     46      * Create the application.
     47      */
     48     public Skip() {
     49         initialize();        //初始化
     50     }
     51 
     52     /**
     53      * Initialize the contents of the frame.
     54      */
     55     private void initialize() {
     56         image = Control.getScreen();            //截取第一个图片
     57         Control.getFoot(image);                    //寻找计算小人位置
     58         Control.getTarget(image);                //寻找目标中心
     59         ImageIcon imageIcon = new ImageIcon(image);        //以截图创建一个ImageIcon对象,供标签使用
     60         
     61         frame = new JFrame();                    //创建一个窗体
     62         frame.setBounds(100, 0, imageIcon.getIconWidth(), imageIcon.getIconHeight());    //设置窗体大小位置
     63         frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        //关闭窗体时结束进程
     64         
     65         lblNewLabel = new JLabel("手机屏幕");        //创建标签
     66         //给标签添加单机时间:单机后开始自动跳跃
     67         lblNewLabel.addMouseListener(new MouseAdapter() {
     68             @Override
     69             public void mouseClicked(MouseEvent e) {
     70                 Thread skip = new Thread(new SkipRun());
     71                 skip.start();
     72             }
     73         });
     74         lblNewLabel.setIcon(imageIcon);            //设置标签图片
     75         frame.getContentPane().add(lblNewLabel, BorderLayout.CENTER);        //添加标签到窗体中
     76     }
     77 
     78     //单步跳跃
     79     protected void skip() {
     80         double distance = Control.getDistance(image);        //计算距离
     81         Control.mouseon(Integer.parseInt(new BigDecimal(String.valueOf(distance * scale)).setScale(0, BigDecimal.ROUND_HALF_UP).toString()));            //模拟触屏
     82         try {
     83             //记录本次图片
     84             ImageIO.write(image, "png", new File("debug" + skipTime++ + ".png"));
     85         } catch (IOException e) {
     86             e.printStackTrace();
     87         }
     88     }
     89     
     90     
     91     //自动跳跃主线程
     92     class SkipRun implements Runnable{
     93 
     94         @Override
     95         public void run() {
     96             //循环跳跃
     97             while(true) {
     98                 skip();
     99                 try {
    100                     //小人跳跃需要花一定时间,在此等待3秒
    101                     Thread.sleep(time);
    102                 } catch (InterruptedException e1) {
    103                     e1.printStackTrace();
    104                 }
    105                 //将当前手机屏幕显示在窗体中
    106                 image = Control.getScreen();
    107                 lblNewLabel.setIcon(new ImageIcon(image));
    108             }
    109         }
    110         
    111     }
    112     
    113 }
    114 
    115 /**
    116  * 工具类,负责发送ADB命令、计算小人与目标距离
    117  */
    118 class Control {
    119     private static int footX = 0, footY = 0;        //小人底部坐标
    120     private static int targetX = 0,targetY = 0;        //目标方块中心坐标
    121     //获取截屏
    122     public static BufferedImage getScreen(){
    123         //截屏
    124         try {
    125             //手机截屏,存储到SD卡
    126             Process process = Runtime.getRuntime().exec("adb shell screencap /sdcard/screen.png");
    127             process.waitFor();
    128             //将截图传到电脑,以便接下来的分析
    129             process = Runtime.getRuntime().exec("adb pull /sdcard/screen.png screen.png");
    130             process.waitFor();
    131         } catch (IOException | InterruptedException e) {
    132             //异常处理
    133             e.printStackTrace();
    134         }
    135         //加载文件
    136         File file = new File("screen.png");
    137         if (file == null || !file.exists()) {
    138             System.out.println("获取截屏失败");
    139             return null;
    140         }
    141         
    142         //加载图片
    143         BufferedImage image = null;
    144         try {
    145             image = ImageIO.read(file);
    146         } catch (IOException e) {
    147             e.printStackTrace();
    148         }
    149         return image;
    150     }
    151     
    152     //长按屏幕
    153     public static void mouseon(int time) {
    154         try {
    155             Runtime.getRuntime().exec("adb shell input swipe 200 200 200 200 " + time);
    156         } catch (IOException e) {
    157             // TODO Auto-generated catch block
    158             e.printStackTrace();
    159         }
    160     }
    161     
    162     //计算距离
    163     public static double getDistance (BufferedImage image) {
    164         getFoot(image);            //获取小人坐标
    165         getTarget(image);        //获取目标坐标
    166         return Math.sqrt((footX - targetX) * (footX - targetX) + (footY - targetY) * (footY - targetY));
    167     }
    168     
    169     public static void getFoot(BufferedImage image){
    170         
    171         Color footColor = new Color(54,60,102);        //小人底部颜色
    172         int top = (int)(image.getHeight() * 0.5);        //扫描范围顶部(X)
    173         int bottom = (int) (image.getHeight() * 0.7);    //扫描范围底部(X)
    174         /*
    175          * 自底向上扫描小人脚下位置
    176          */
    177         for(int i = bottom;i > top;i--)
    178         {
    179             for(int j = 0;j < image.getWidth();j++)
    180             {
    181                 //如果当前颜色与小人脚部颜色相近
    182                 if(Math.abs(image.getRGB(j, i) - footColor.getRGB()) < 200) {
    183                     footX = j;
    184                     footY = i - 10;        //自左向右扫描,原始结果会偏左,在此稍向右移
    185                     i = top;        //结束外层循环
    186                     break;
    187                 }
    188             }
    189         }
    190         /*
    191          * 用蓝色方块标记找到的小人位置
    192          */
    193         Graphics g = image.getGraphics();
    194         g.setColor(Color.BLUE);
    195         g.fillRect(footX - 5, footY - 5, 10, 10);
    196     }
    197     
    198     public static void getTarget(BufferedImage image) {
    199         
    200         /*
    201          * 第一步,找到目标方块上端顶点,该顶点的X坐标即中心的X坐标
    202          */
    203         
    204         int top = (int)(image.getHeight() * 0.35);            //扫描范围顶部
    205         int bottom = (int)(image.getHeight() * 0.49);        //扫描范围底部
    206         Color headColor = new Color(56, 54, 71);
    207         /*
    208          * 自顶向下扫描目标方块顶端位置
    209          */
    210         for(int i = top;i < bottom;i++)
    211         {
    212             Color bgColor = new Color(image.getRGB(10, i));        //取背景色
    213             for(int j = 0;j < image.getWidth();j++)
    214             {
    215                 /*
    216                  * 小人可能高于目标方块,为排除干扰,略过小人所在的纵坐标(列)
    217                  */
    218                 if (j >= footX - 30 && j <= footX + 30) {
    219                     continue;
    220                 }
    221                 Color color = new Color(image.getRGB(j, i));    //取当前颜色
    222                 int t = 0;
    223                 t = Math.abs(bgColor.getRGB() - color.getRGB());    //计算色差
    224 
    225                 if (t > 200000){    //如果与背景色不同
    226                     targetX = j;    //记录行坐标
    227                     targetY = i;    //记录纵坐标
    228                     i = bottom;        //结束外层循环
    229                     break;            //结束内层循环
    230                 }
    231             }
    232         }
    233         
    234         /*
    235          * 第二步,从顶点开始,向下扫描,找到方块占据最多列的那一行,即为目标的Y坐标
    236          */
    237         
    238         int maxLength;            //方块的直径
    239         int x = targetX;        //行扫描起始坐标
    240         int y = targetY;        //直径所在行(y坐标)
    241         
    242         /*
    243          * 如果在下面多行,该方块占据的列都相同,说明本行是中心所在行,
    244          * 即Y坐标就是本行。使用flag记录连续相同的行数
    245          */
    246         
    247         int flag = 0;            //不满足条件标志
    248         for(int i = y + 1;i < y + 101 && flag < 8;i++)        //当连续8行直径相同后,结束循环
    249         {
    250             for(int j = x;j < image.getWidth();j++)
    251             {
    252                 Color bgColor = new Color(image.getRGB(image.getWidth() - 10, i));        //取背景色
    253                 Color color = new Color(image.getRGB(j, i));        //取当前颜色
    254                 if (( Math.abs(bgColor.getRGB() - color.getRGB())) <= 703400) {        //如果与背景色颜色相近
    255                     if (j > x) {        //当前x坐标大于之前的x,(说明方块在本行占据的列更多)
    256                         x = j;            //当前x坐标赋值给x
    257                         targetY = i;    //直径所在行替换为当前y
    258                         flag = 0;
    259                     }else {                //当前x坐标不大于之前的x,(说明方块在本行占据的列不是最多)
    260                         flag++;            //此标志+1            
    261                     }
    262                     break;
    263                 }
    264             }
    265         }
    266         targetY = targetY - flag;        //减去多加的flag
    267         
    268         /*至此,targetX与targetY寻找完毕*/
    269         /*
    270          * 用红色方块记录目标点
    271          */
    272         Graphics g = image.getGraphics();
    273         g.setColor(Color.RED);
    274         g.fillRect(targetX - 5, targetY - 5, 10, 10);
    275     }
    276 }

    ---恢复内容结束---

  • 相关阅读:
    MFC调用C动态库函数-----待补充
    硬盘知识总结:
    Android 四:区分刷机与root
    总结:Linux系统启动流程
    Android 三:手机adb 命令解锁
    UVa11136 Hoax or what
    UVa11988 Broken Keyboard (a.k.a. Beiju Text)
    UVa11280 Flying to Fredericton
    UVa10269 Adventure of Super Mario
    UVa12589 Learning Vector
  • 原文地址:https://www.cnblogs.com/lzq666/p/8352382.html
Copyright © 2020-2023  润新知