七的博客

微信跳一跳小游戏辅助

Android

微信跳一跳小游戏辅助

最近微信发布了新版本,加入了【小游戏功能】,同时官方提供了一个测试小游戏【跳一跳】。

跳一跳就是一个插画风格额游戏,玩家通过按住屏幕蓄力,然后小人会根据你蓄力的长短跳跃到前方。 而且官方还把分数跟朋友圈进行排名,导致朋友圈最近非常多人在跳跳跳。

不过这游戏需要你准确的把握好蓄力的时间,才能精准跳到对应的格子上。

观察这游戏的特点,其实可以通过计算距离来预估蓄力的时间。开搞!

大致原理

简单来说,就是利用了安卓手机可以直接通过 ADB 程序进行截图。然后截图传送到电脑上,电脑上去计算当前点跟目标点的距离,然后通过距离计算蓄力的时间来达到跳的准的目的。

流程如下:

  • 安卓手机打开跳一跳程序,同时连接到电脑。
  • 在 IDEA 中启动辅助程序。
  • 程序会通过 ADB 命令对手机当前屏幕进行截图。
  • 将截图传送到电脑,电脑上实时将图片渲染到电脑程序框里。
  • 用户通过鼠标手动点击起始位置,然后再点击下一个目标。
  • 程序计算出当前坐标跟下个目标之间的距离,根据手机屏幕大小等计算蓄力的事件。
  • 通过 ADB 程序发送触摸屏幕指定坐标以及触摸时间给手机。
  • 手机根据指令将小人跳到指定的目标。

需要掌握的技能

  • 懂 Java 基本语法
  • 了解一点 ADB 指令
  • 了解一点 Java AWT 或者 Swing 界面编程概念
  • 了解计算 2 个坐标点之间的距离 (即 开根号((x1 - x2)^2 + (y1 - y2)^2))

环境

  • 操作系统: Ubuntu 16.04
  • JDK: JDK 1.8
  • IDE: IDEA 2017.1.3
  • ADB 24.3.4
  • 安卓手机

ADB 驱动安装

ADB 是一个安卓设备调试工具,全程是 Android Debug Bridge。 经常刷机或者玩软件逆向的应该很熟悉,这里就不说这么详细了。

根据你的操作系统使用不同的方式安装 ADB

  • Ubuntu 下直接从仓库安装即可
  sudo apt-get install -y android-tools-adb
  
  # 如果仓库里没有的话添加下源
  sudo add-apt-repository ppa:nilarimogard/webupd8 
  sudo apt-get update 
  sudo apt-get install -y android-tools-adb 
  • Windows 需要下载一个压缩包,然后将压缩包解压到你电脑本地,然后将解压的目录配置到环境变量 path 中。跟配置 JDK 环境变量类似的套路, ADB 就是一堆程序的集合。不过由于国内众所皆知的网络原因,是不能直接从谷歌官网下载,可以通过魔法进行下载或者直接在国内网上下载即可。

安装完成后,打开命令行输入:

adb version

如果出现 Android Debug Bridge version x.x.xxx 的字眼则说明环境变量配置成功。

连接设备

这里简单点直接通过数据线连接即可,连接后命令行输入:

adb devices

如果出现下面的字眼则说明检测成功:

* daemon not running. starting it now on port 5037 *
* daemon started successfully *
List of devices attached 
xxxx device

直接执行下面的命令连接即可:

adb shell 

编码

先编写几个基础的类。

首先编写坐标点对象:

package com.suny.weixin.jump;

/**
 * 2018-2-5
 */
public class Point {
	public int x;
	public int y;

}

编写截图工具类:

/**
 * 2018-2-5
 */
public class ScreenshotUtils {
    
    public static void jump(int time) {
        try {
            out.println("自动跳到指定的坐标");
            out.println("\n");
            String command = String.format("adb shell input touchscreen swipe 170 187 170 187 %d", time);
            Runtime.getRuntime().exec(command);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public static void captureScreenshot() {
        try {
            String screenshotCommand = "adb shell screencap -p /sdcard/jump.png";
            String pullCommand = "adb pull /sdcard/jump.png /home/xxx/Downloads/jump.png";
            
            Process screenshotProcess = Runtime.getRuntime().exec(screenshotCommand);
            screenshotProcess.waitFor();
            
            Process pullProcess = Runtime.getRuntime().exec(pullCommand);
            out.println("【" + LocalTime.now() + "】刷新手机界面到PC");
            pullProcess.waitFor();
        } catch (Exception e) {
            out.print("是否还没有连接手机");
        }
    }
    
}

创建一个面板:

package com.suny.weixin.jump;

import java.awt.Graphics;
import java.awt.Image;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * 2018-2-5
 */
public class PhonePanel extends JPanel{

	private static final long serialVersionUID = 1L;
	private static final String JUMP_PNG = "/home/xxx/Downloads/jump.png";

	@Override
	public void paint(Graphics g){
		try {
			ScreenshotUtils.captureScreenshot();
			// 手机截屏的路径自己根据实际的调整
			Image image = ImageIO.read(new File(JUMP_PNG));
			//  图像展示大小需要自己设定,这里用的我手机的,根据各自的手机屏幕大小调整
			g.drawImage(image, 0, 0, 540, 960, null);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

首先先编写一个 Java 界面主程序:

package com.suny.weixin.jump;

import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.*;

import static java.lang.System.out;


/**
 * 2018-2-5
 */
public class WeixinJumpGameFrame extends JFrame {
    
    // 显示手机屏幕图像的面板
    private PhonePanel phoneImgPanel = null;
    
    // 否为第一次点击
    private boolean isFirst = true;
    
    // 上一次点击的点的坐标
    private final transient Point prePoint = new Point();
    
    // 当前点击的点的坐标
    private final transient Point curPoint = new Point();

    private StartGame() {
        // 创建手机屏幕图像面板
        phoneImgPanel = new PhonePanel();
        
        this.add(phoneImgPanel);

        // 窗口的大小为540x960像素,这里需要根据你的手机大小调整
        this.setSize(540, 960);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.setTitle("跳一跳辅助");
        phoneImgPanel.addMouseListener(new MouseListener() {
            @Override
            public void mousePressed(MouseEvent event) {
                // 如果是第一次点击
                if (isFirst) {
                    // 记录点击的坐标为起跳点坐标
                    prePoint.x = event.getX();
                    prePoint.y = event.getY();
                    // false表示已经记录了起跳点
                    isFirst = false;
                    // 输出当前小球的坐标
                    out.println("当前小球坐标是【" + prePoint.x + "," + prePoint.y + "】");
                    return;
                }

                // 如果不是第一次点击,记录点击的坐标为目标站台坐标
                curPoint.x = event.getX();
                curPoint.y = event.getY();
                // 输出目标站台的坐标
                out.println("目标站台坐标是【" + curPoint.x + "," + curPoint.y + "】");

                // 计算起跳点和目标站台之间的距离
                final int distance = calDistance(prePoint, curPoint);
                // 根据距离计算跳跃的时间,这里使用了一个固定的比例系数0.37,记得改,大手机小手机会有差异
                final int time = (int) (distance / 0.37);
                // 执行跳跃操作
                ScreenshotUtils.jump(time);

                // 等待3秒让手机屏幕更新
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
				 // 刷新图像面板,获取最新的手机屏幕图像
                isFirst = true;
               
                phoneImgPanel.validate();
                phoneImgPanel.repaint();
            }

            @Override
            public void mouseReleased(MouseEvent event) {
            }

            @Override
            public void mouseExited(MouseEvent event) {
            }

            @Override
            public void mouseEntered(MouseEvent event) {
            }

            @Override
            public void mouseClicked(MouseEvent event) {
            }
        });
    }
    
    private static int calDistance(Point p1, Point p2) {
    	int dx = p1.x - p2.x;
    	int dy = p1.y - p2.y;
    	int distance = (int) Math.sqrt(dx * dx + dy * dy);
    	out.println("两点间距离为" + distance);
    	return distance;
	}

    public static void main(String[] args) {
        // 输出程序开始的提示信息
        out.println("==========跳一跳辅助开始==============");
        out.println("\n");
        out.println("\n");
        out.print("当前机型【小米MAX2】,分辨率【1920 x 1080】");
        new StartGame();
    }
    
}

测试

  • 打开手机的跳一跳游戏界面。
  • 使用 USB 线或者是远程 ADB 连上手机。
  • 启动 IDEA 上的程序。
  • 鼠标先点击起始位置一下。
  • 再用鼠标点击下一个目标站台,可以看到小人会准确跳过去。

注意事项

  • 每个人手机屏幕大小不一样,需要多调试几次。
  • 官方检测还是挺严格的,注意别刷太多分,毕竟游戏还是以娱乐为主。