您的位置:首页 > 编程语言 > Java开发

JAVA实现跳一跳辅助程序之虎啸龙吟

2018-01-16 10:00 369 查看

实现原理:


每次跳跃之前,截取一下手机屏幕,并将截图保存到本地电脑中;
计算截图中人偶的位置与将要跳至的台面中心的距离dd;
将以上距离dd换算成相应的触摸时间ss;
发送模拟触摸的命令至手机,触摸时间为以上时间ss;

重点是要计算出人偶与将要跳至的台面中心的距离,需要分别识别出人偶的位置(坐标)和台面中心的位置(坐标)。

我们以人偶最底部的一行的中心作为人偶的位置,如下图所示:



至于怎么识别出人偶的最底部,可以这样来操作。通过观察可发现,人偶底部的颜色的rgb值在(53, 57, 95)到(59, 61, 103)之间,因此我们逐行扫描各个像素点,找到rbg值在该区间的各行,最后一行即为人偶的底部了。得到了最底部的一行,自然就能算出该行的中心坐标。

接下来需要识别人偶将要跳至的平台的中心。要想得到该中心的坐标,我们只需要识别得到下图中的两个顶点vertex1和vertex2的坐标即可:



我们同样用从左往右,从上往下的顺序扫描各个像素点的方法来找出vertex1的坐标。扫描之前先获取整个背景的颜色的rgb值,取任意“空白”处即可(例如本人手机截图大小为1920x1080,可断定坐标为(40, 500)的点一定处于“空白”处。)。在扫描过程中一旦发现某处的颜色与背景色不一致,发生了“突变”,可断定该点即为vertex1。

我们把vertex1点的rgb值记录下来作为台面的背景色。在接下去的扫描过程中,我们开始关心当前扫描的点的rgb值是否和该记录值“相似”。“相似”则说明该点“属于”台面,而通过上图可发现,顶点vertex2是所有“属于”台面的点中,横坐标最小的点,这样vertex2的坐标也找到了。

显然,台面中心的横坐标等于vertex1的横坐标,而纵坐标等于vertex2的纵坐标。


步骤3

通过多次尝试,发现用如下公式转换距离dd(单位:px)为时间ss(单位:毫秒)比较合适:

s=d∗1.35

可参考:https://www.cnblogs.com/dongkuo/p/8285162.html ,在此表示感谢

代码实现:

1 package code;
2
3 import java.awt.AWTException;
4 import java.awt.Graphics2D;
5 import java.awt.Transparency;
6 import java.awt.image.BufferedImage;
7 import java.io.File;
8 import java.io.IOException;
9 import java.io.InputStreamReader;
10 import java.io.LineNumberReader;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.TreeMap;
14 import javax.imageio.ImageIO;
15
16 public class Jump {
17     //存放图片的路径
18     static String file1 = "C:\\Users\\JJJ\\Desktop\\jump3.jpg";
19     //始 扫描行,针对不同的手机分辨率可能不一样,需要修改,此处建议手工测量下坐上角跳跃步数的数字位置,估算出起始行  楼主的手机是se 像素是 1156*640
20     static int start_y = 200;
21     static boolean istest = false;
22     static int background_x = 10;   //定义默认的背景色,一定是不会出现其他物体的位置
23     static int background_y = 580;
24
25     public static void main(String[] args) throws AWTException, InterruptedException, IOException {
26          istest = true;
27
28
29             System.out.println("开始:计算" + file1);
30             if (istest) {
31                 cmd_java("cmd /c start adb.bat ", "C:\\Users\\JJJ\\Downloads\\cofface_adb\\cofface_adb_windows_v5.1");//批处理文件
32             }
33             BufferedImage bi = (BufferedImage) ImageIO.read(new File(file1));
34             Map<Integer, Integer> treemap = new TreeMap<Integer, Integer>();
35             // 获取图像的宽度和高度
36             int width = bi.getWidth();
37             int height = bi.getHeight();
38             //小人中心点坐标
39             int poix = 0;
40             int poiy = 0;
41             //目标物体的最顶点X轴 和左边或右边的Y轴
42             int mubiaopoix1 = 0;
43             int mubiaopoiy2 = 0;
44             //目标中心点坐标
45             int mubiaopoix = 0;
46             int mubiaopoiy = 0;
47             BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
48             Graphics2D g2d = img.createGraphics();
49             // 设置画布为透明
50             img = g2d.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT);
51            // 扫描图片,获取小人的底部中心坐标
52             for (int i = start_y; i < height; i++) {
53                 for (int j = 0; j < width; j++) {// 行扫描
54                     int dip = bi.getRGB(j, i);
55                     int p = dip;
56                     int red = 0xff & (p >> 16);
57                     int green = 0xff & (p >> 8);
58                     int blue = 0xff & p;
59                     // 目标人图形
60                     if (i < (height / 1.5))
61                     {
62                         if ((red > 53 && red < 59) && (green > 57 && green < 61) && (blue > 59 && blue < 103))
63                         {  // 获取小人坐标,从中取除Y值最大的一个
64                             treemap.put(i, j);
65                         }
66                     }
67                 }
68             }
69             //获取最后的小人底部坐标 ,此处使用treemap 直接排好序,循环获取Y轴值最大的一个
70            for (Entry<Integer, Integer> entry : treemap.entrySet())
71            {
72                poiy = entry.getKey();
73                poix = entry.getValue();
74            }
75            //开始扫描目标物体的最上 和最左坐标 ,扫描的Y最大值为当前小人的Y值
76            treemap.clear(); //清除前面的记录,准备存放目标物体的坐标
77            RGB rgb = null;
78            boolean frist = true;
79            RGB rgb_0 = pixToRgb(bi, background_x, background_y);  //默认的背景色
80            for (int y = start_y; y < poiy; y++) {
81                int x = 0;
82                if (poix < width /2) //此处特别说明下,如果小人的坐标在整个屏幕的左边,则目标物体一定在右边,遂起始x轴加20开始循环,反之则不用
83                {
84                    x  = poix + 20;
85                }
86                else
87                {
88                    x  = 20;
89                }
90                for (; x < width - 20; x++) {// 行扫描
91                    int dip = bi.getRGB(x, y);
92                    int p = dip;
93                    RGB rgb_1 = pixToRgb(bi, x, y);
94                    if(frist && rgbCz(rgb_0,rgb_1,10))  //如果不相同则说明找到了第一个点
95                    {
96                        mubiaopoix1 = x;
97                        rgb = rgb_1;
98                        frist = false;
99                        continue;
100                    }
101                    if (!frist && rgbBcz(rgb,rgb_1,10))
102                    {
103                        treemap.put(x, y);  //存放所有当前台面的像素点坐标,然后从中选出X值最小的一个,
104                    }
105                }
106            }
107            //获取目标物体的坐标,如果是在右半边,则获取最后一个值的Y轴,如果是在左边,则获取第一个
108            if (poix > width / 2)
109            {
110                for (Entry<Integer, Integer> entry : treemap.entrySet())
111                {
112                    mubiaopoiy2 = entry.getValue();
113                    break;
114                }
115            }
116            else
117            {
118                for (Entry<Integer, Integer> entry : treemap.entrySet())
119                {
120                    mubiaopoiy2 = entry.getValue();
121                }
122            }
123            //通过获取的2个点坐标计算出中心点位置
124            mubiaopoix = mubiaopoix1;
125            mubiaopoiy = mubiaopoiy2;
126            //计算 小人与目标人物的举例
127            int total = (mubiaopoix - poix) * (mubiaopoix - poix) + (mubiaopoiy - poiy) * (mubiaopoiy - poiy);
128            double length = (double) Math.sqrt(total);
129            double time =  length * 1.35; //时间系数
130            System.out.println("小人的坐标为:" + poix + "," + poiy);
131            System.out.println("目标物体的坐标为:" + mubiaopoix + "," + mubiaopoiy);
132            System.out.println("需要按压屏幕的时间为:" + time + "毫秒");
133         }
134
153
154     static InputStreamReader ir = null;
155     static LineNumberReader input = null;
156
157     public static void cmd_java(String cmd) throws IOException {
158         Process process = Runtime.getRuntime().exec(cmd, null, new File("C:\\Users\\chenyd\\adb"));
159         ir = new InputStreamReader(process.getInputStream());
160         input = new LineNumberReader(ir);
161         while (input.readLine() != null) {
162         }
163         input.close();
164         ir.close();
165     }
166
167     public static void cmd_java(String cmd, String url) throws IOException {
168         Process process = Runtime.getRuntime().exec(cmd, null, new File(url));
169         ir = new InputStreamReader(process.getInputStream());
170         input = new LineNumberReader(ir);
171         while (input.readLine() != null) {
172             System.out.println(11);
173         }
174         input.close();
175         ir.close();
176     }
177
178     /**
179      * 颜色的差值不在范围内
180      */
181     public static boolean rgbCz(RGB rgb_1, RGB rgb_2, int fd_rgb) {
182         if (Math.abs(rgb_1.getRed() - rgb_2.getRed()) > fd_rgb && Math.abs(rgb_1.getGreen() - rgb_2.getGreen()) > fd_rgb
183                 && Math.abs(rgb_1.getBlue() - rgb_2.getBlue()) > fd_rgb) {
184             return true;
185         }
186         return false;
187     }
188
189     /**
190      * 颜色的差值在范围内
191      */
192     public static boolean rgbBcz(RGB rgb_1, RGB rgb_2, int fd_rgb) {
193         if (Math.abs(rgb_1.getRed() - rgb_2.getRed()) < fd_rgb && Math.abs(rgb_1.getGreen() - rgb_2.getGreen()) < fd_rgb
194                 &&  Math.abs(rgb_1.getBlue() - rgb_2.getBlue()) < fd_rgb) {
195             return true;
196         }
197         return false;
198     }
199
200     public static RGB pixToRgb(BufferedImage bi, int j, int i) {
201         try {
202             int dip = bi.getRGB(j, i);
203             int p = dip;
204             int red = 0xff & (p >> 16);
205             int green = 0xff & (p >> 8);
206             int blue = 0xff & p;
207             return new RGB(j, i, red, green, blue);
208         } catch (Exception e) {
209
210         }
211         return null;
212     }
213
214 }
215
216 class RGB {
217
218     public RGB() {
219     }
220
221     public RGB(int x, int y, int red, int green, int blue) {
222         super();
223         X = x;
224         Y = y;
225         this.red = red;
226         this.green = green;
227         this.blue = blue;
228     }
229
230     public int X;
231     public int Y;
232     public int red;
233     public int green;
234     public int blue;
235
236     public int getRed() {
237         return red;
238     }
239
240     public void setRed(int red) {
241         this.red = red;
242     }
243
244     public int getGreen() {
245         return green;
246     }
247
248     public void setGreen(int green) {
249         this.green = green;
250     }
251
252     public int getBlue() {
253         return blue;
254     }
255
256     public void setBlue(int blue) {
257         this.blue = blue;
258     }
259
260     public int getX() {
261         return X;
262     }
263
264     public void setX(int x) {
265         X = x;
266     }
267
268     public int getY() {
269         return Y;
270     }
271
272     public void setY(int y) {
273         Y = y;
274     }
275
276 }


由于楼主目前没有安卓设备,还无法带上adb实验,目前只是通过手动截取图片,和测量距离计算了3张,总体比较下来,还算是正确的。
第一张图片



计算结果如图:



第二张图片



计算结果如图:



第三张图片



计算结果如图:



后续再搞个安卓设备试试~
吐槽一下,博客园,tmzz,说我排版不好,从首页下架,尼玛~
原文出自:http://www.cnblogs.com/JJJ1990/p/8289401.html

give me the ball!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: