前两周用java实现了自动玩微信跳一跳游戏,经过两次优化,目前每次计算的准确率得到了大幅提升,跟大家分享一下实现算法。
首先看一下自动玩微信跳一跳游戏的实现原理:
- 手机打开USB调试模式,通过adb连接手机
- 通过adb命令截屏抓取游戏页面:adb shell screencap 及adb pull 命令
- 计算出屏幕中黑棋到目标块的距离
- 根据距离及时间系数计算出按压时间
- 通过adb命令按压屏幕,实现跳到下一步:adb shell input swipe 命令
可以看出,要提高准确率,关键要提高获取黑棋到目标块的距离。
获取黑棋的中心坐标方法
BufferedImage bi = ImageIO.read(pic);
//获取图像的宽度和高度
int width = bi.getWidth();
int height = bi.getHeight();
int x1 = 0, y1 = 0;
for (int i = 50; i < width; i++) {
for (int flag = 0, j=height*3/4; j>height/3; j -= 5) {
//判断点的颜色是否跟RGB(55,58,100)黑色相近
if (!colorDiff(bi.getRGB(i,j),55<<16|58<<8|100)) flag++;
//如果有3个以上的点是黑色,则认为找到了黑棋
if (flag > 3) {
x1 = i + 13;//相加少量修正值
y1 = j + 2; //相加少量修正值
break;
}
}
if (x1 > 0) break;
}
System.out.println(x1+":"+y1);
其中以上用于判断颜色相近的方法为:
boolean colorDiff(int c1, int c2){
int c11 = c1>>16 & 0xFF,c12 = c1>>8 & 0xFF,c13 = c1 & 0xFF;
int c21 = c2>>16 & 0xFF,c22 = c2>>8 & 0xFF,c23 = c2 & 0xFF;
return Math.abs(c11 - c21) > 5 || Math.abs(c12 - c22) > 5 || Math.abs(c13 - c23) > 5;
}
获取目标块的中心坐标方法
int x2 = 0, y2 = 0;
for (int i = height / 3; i < y1; i++) {
int p1 = bi.getRGB(99, i);//获取扫描起始点颜色
for (int j = 100; j < width; j++) {
//找到不是纯色的线条,从而找到目标块顶点
if (colorDiff(bi.getRGB(j,i),p1)) {
if(Math.abs(j-x1)<50) {//黑棋比目标块高
j = j + 50;
}else {//找到了目标块顶点
x2 = j;
y2 = i;
break;
}
}
}
if (x2 > 0) {//找到了目标块顶点
int p2 = bi.getRGB(x2, y2 - 10),j,max = -1;
//固定顶点横坐标,计算目标块的宽度
for (; i < y1-50;i += 5 ) {
for (j = x2; colorDiff(bi.getRGB(j,i),p2) && j<x2+200;) j++;
//如果目标是圆形,顶点会是一条线,需要修顶点正横坐标
if(max < 0 && j-x2>0) x2 = x2 + (j-x2)/2;
if(max < j - x2) max = j - x2;//找到目标块最长宽度
else break;
}
//顶点横坐标及目标块最长宽度所在线纵坐标即目标块中心点坐标
y2 = i - 5;//减去少量修正值
break;
}
}
//通过以上方法能获取到大部分目标图形的中心点,除了咖啡杯等图案稍微不太准确
通过以上方法获取到两个中心点的坐标后,只要计算出距离,就可以计算出需要按压的时间
计算按压时间
double distance = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
if (distance < 150) distance = 150;
//距离需要乘一定的时间系数,才能得到对应的时间
int time = (int) (distance * rate);
更多代码详情,请见:
https://gitee.com/hylun/AutoPlayWechatJumpGame
https://github.com/hylun/AutoPlayWechatJumpGame