微信跳一跳这个小游戏很火,网上已经出现了很多“辅助”,大部分都可以让你拿高分,常年稳置榜首,9999分不是梦。
我出于兴趣,使用Java也写了一个,只能在Android上玩,我写这个不是为了拿高分,测试的时候是离线下测试的,就是想写来玩一玩。
大概思路如下:
- 电脑通过数据线连接手机。
- 通过 adb shell screencap -p /*.* 让手机截屏并保存到SD卡。
- 使用 adb pull /sdcard/*.* *://*.* 把手机里的图片拉取到电脑。
- 分析得到的图片从而计算模拟按键时间。
分析图片
看这张图片,我们需要找到两个来确定跳跃的距离,第一个点是人物脚下的点,第二个点是目标跳板的中点。
我直接遍历这张图的每一个像素点,但有点地方是可以忽略的,如上面的1/3和下面的1/3区域。
人物的点很好找,用PS打开图片,放大再放大
查看中间点的rgb值,一般都可以较准确的找到人物的中点,但有极少数情况会找不到。
而目标跳板的中点就有点麻烦了,跳板的形状有正方形,圆形,我们可以找到两个点来确定跳板的中点,最上面和最下面的点。
手机屏幕的坐标左上角为(0,0),从上到下,从右到左遍历图片,把遍历的每一个点的rgb值和背景(同一行最左或最右的像素点,因为背景色会从上到下渐变)比较,如果和背景色不同,那么目标的最上点就找到了。
接着找最下点,因为最上点已知了,最下点的查找范围就设置在最上点的左右,用同样方法即可找到。
取上下两点的中间就是目标跳板的中点了。
最后计算人物到目标跳板的距离
使用公式即可。
最后模拟按键时间通过使用距离乘上一个常熟得到,常数是多少,不知道,多试几下可以大概猜出,我用的是1.436 。
这个代码还不完美,只能玩400分左右。。。有时又能700分,不过,毕竟是自己写的,没法和GitHub上热门的比,已经较满意了,看心情决定要不要继续写,哈哈。
代码:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.imageio.ImageIO;
public class Main {
private static int image = 0;
public static void main(String[] args) throws Exception {
while (true) {
//截图到手机
cmd("adb shell screencap -p /sdcard/.a/" + image + ".png");
//从手机拉取图片到电脑
new File("e:/" + image + ".png").createNewFile();
cmd("adb pull /sdcard/.a/" + image +".png " + "e:/" + image + ".png");
//计算按键时间并模拟按键
int pressTime = (int) (get_pressTime()*1000/1000);
cmd("adb shell input swipe 550 1600 550 1600 " + pressTime);
System.out.println("按键时间为:"+pressTime);
System.out.println("-----------");
//模拟右滑
//cmd("adb shell input swipe 850 1600 550 1600 400");
image++;
TimeUnit.MILLISECONDS.sleep(1000);
}
}
//计算按键时间
private static double get_pressTime() throws IOException {
File file = new File("e:/" + image + ".png");
BufferedImage img = ImageIO.read(file);
int width = img.getWidth();
int height = img.getHeight();
int[] s = s_xy(img, width, height);
if (s == null) {
System.out.println("游戏结束!");
System.exit(0);
}
//cmd("adb shell input swipe " +s[0]+" "+s[1]+" "+s[0]+" "+s[1]+" 2000");
System.out.println("人的位置:" + s[0] + " " + s[1]);
int[] o = o_xy(img, width, height);
if (o == null) {
System.out.println("游戏结束!");
System.exit(0);
}
//cmd("adb shell input swipe " +o[0]+" "+o[1]+" "+o[0]+" "+o[1]+" 2000");
System.out.println("目标垫子:" + o[0] + " " + o[1]);
double d = Math.sqrt(Math.abs((o[0]-s[0]) * (o[0]-s[0]) + (o[1]-s[1]) * (o[1]-s[1])));
System.out.println("两点距离:" + d);
img.flush();
return d * 1.436;
}
//寻找人的位置
private static int[] s_xy(BufferedImage img, int width, int height) {
int[] s = { 0, 0 };
for (int y = height/3; y < height - height/3; y++) {
for (int x = width/5; x < width; x++) {
int rgb = img.getRGB(x, y);
int r =(rgb & 0xff0000 ) >> 16 ;
int g= (rgb & 0xff00 ) >> 8 ;
int b= (rgb & 0xff );
if (r == 57 && g == 59 && b == 102) {//脚底的rgb
s[0] = x;
s[1] = y;
return s;
}
}
}
return null;
}
//寻找目标跳板中点
private static int[] o_xy(BufferedImage img, int width, int height) {
int[] o = { 0, 0 };
for (int y = height/3; y < height-height/3; y++) {
for (int x = width-2; x > 0; x--) {
//右边对比点
int trgb = img.getRGB(width-1, y);
int tr = (trgb & 0xff0000) >> 16 ;
int tg = (trgb & 0xff00) >> 8 ;
int tb = (trgb & 0xff);
//当前点
int rgb = img.getRGB(x, y);
int r = (rgb & 0xff0000) >> 16 ;
int g = (rgb & 0xff00) >> 8 ;
int b = (rgb & 0xff);
//人头挡住
if ((r <= 75 && r >= 50) && (g <= 76 && g >= 50) && (b <= 109 && b >= 50) && x >= 70) {
//跳到人头左边
x = x - 70;
rgb = img.getRGB(x, y);
r = (rgb & 0xff0000) >> 16 ;
g = (rgb & 0xff00) >> 8 ;
b = (rgb & 0xff);
}
//找到跳板的最上点,和背景的rgb值做对比,加点误差范围
if ((r <= tr-3 || r >= tr+3) && (g <= tg-3 || g >= tg+3) && (b <= tb-4 || b >= tb+3) ||
(r <= tr-3 || r >= tr+3) || (g <= tg-3 || g >= tg+3) && (b <= tb-4 || b >= tb+3) ||
(g <= tg-3 || g >= tg+3) || (b <= tb-3 || b >= tb+3) && (r <= tr-4 || r >= tr+3))
{
/*
o[0] = x;
o[1] = y;
return o;*/
//药瓶
if (rgb == img.getRGB(x-5, y) && r == 255 && g == 255 & b == 255) {
x -= 5;
for (int by = y + 60; by > y; by--) {
for (int bx = x + 30; bx > x - 30; bx--) {
if (img.getRGB(bx, by) == rgb) {
o[0] = (x + bx)/2;
o[1] = (y + by)/2;
return o;
}
}
}
}
//正方形跳板 找最下的点
for (int by = y + 260; by > y; by--) {
for (int bx = x + 60; bx > x - 60; bx--) {
if (img.getRGB(bx, by) == rgb) {
o[0] = (x + bx)/2;
o[1] = (y + by)/2;
return o;
}
}
}
}
}
}
return null;
}
//调用命令行
private static void cmd(String command) {
Process process = null;
try {
process = Runtime.getRuntime().exec(command);
process.waitFor();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (process != null) process.destroy();
}
}
}