微信跳一跳辅助Java代码实现

时间:2022-09-13 10:23:12

微信跳一跳辅助的Java具体实现代码,供大家参考,具体内容如下

1.参考知乎教你用Python来玩微信跳一跳,鉴于本人Python一直都是半吊子水平,之前打算用python刷分,可无奈安装python环境各种模块缺失,报错不停,于是乎,使用Java重新实现了一下。

2.环境配置及相关说明:

1)、Windows系统,本人win10
2)、AVA环境安装,JDK7以上即可
3)、安卓手机一部、数据线一条
4)、电脑安装ADB驱动,连接安卓手机,同时打开USB调试模式
5)、打开微信小程序的跳一跳游戏,JAVA程序跑起来,具体代码往下看
6)、本人所用为魅蓝note2安卓手机,屏幕 分辨率1920x1080,不同型号的手机,可能需要调整相关参数,具体看代码注释
7)、增加了刷分失败后游戏自动重新开局功能
8)、娱乐而已,不要较真,据说微信官方已经关注,分数太高可能会被清零,哈哈

3、废话不多说,上代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
package com.yihusitian.gamehelper;
 
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;
 
/**
 * 参考知乎
 *
 * @link <a href="https://zhuanlan.zhihu.com/p/32452473" rel="external nofollow" rel="external nofollow" target="_blank">https://zhuanlan.zhihu.com/p/32452473</a>
 *
 * 跳一跳辅助
 *
 * @author LeeHo
 */
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 = 1.35;
 
 //按压的起始点坐标,也是再来一局的起始点坐标
 private final int   swipeX     = 550;
 
 private final int   swipeY     = 1580;
 
 //二分之一的棋子底座高度
 private final int   halfBaseBoardHeight  = 20;
 
 //棋子的宽度,从截屏中量取,自行调节
 private final int   halmaBodyWidth   = 74;
 
 //游戏截屏里的两个跳板的中点坐标,主要用来计算角度,可依据实际的截屏计算,计算XY的比例
 private final int   boardX1     = 813;
 
 private final int   boardY1     = 1122;
 
 private final int   boardX2     = 310;
 
 private final int   boardY2     = 813;
 
 /**
  * 获取跳棋以及下一块跳板的中心坐标
  *
  * @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 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 > 50 && rValue < 60 && gValue > 53 && gValue < 63 && bValue > 95 && bValue < 110)
    {
     halmaXSum += x;
     halmaXCount++;
     //棋子底行的Y坐标值
     halmaYMax = y > halmaYMax ? y : halmaYMax;
    }
   }
  }
 
  if (halmaXSum != 0 && halmaXCount != 0)
  {
   //棋子底行的X坐标值
   int halmaX = halmaXSum / halmaXCount;
   //上移棋子底盘高度的一半
   int halmaY = halmaYMax - halfBaseBoardHeight;
   //从gameScoreBottomY开始
   for (int y = gameScoreBottomY; y < height; y++)
   {
    processRGBInfo(bufferedImage, 0, y);
    int lastPixelR = this.rgbInfo.getRValue();
    int lastPixelG = this.rgbInfo.getGValue();
    int lastPixelB = this.rgbInfo.getBValue();
    //只要计算出来的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)) > 10)
     {
      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
  * @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)
  {
   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 shell input swipe %s %s %s %s %s", swipeX, swipeY, swipeX, swipeY,
    pressTime);
  System.out.println(command);
  executeCommand(command);
 }
 
 /**
  * 再来一局
  *
  * @author LeeHo
  * @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
  * @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));
 }
 
 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();
  }
 }
 
 /**
  * 检查是否需要重新开局
  *
  * @author LeeHo
  * @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
  * @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));
 }
 
 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;
  }
 }
}

 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://blog.csdn.net/lihushiwoa/article/details/78942322