《家国梦》游戏自动化测试

《家国梦》是最近很火的一款不用氪金的手游,在周围同窗好友的怂恿下,我走上了“不归路”。这游戏玩法至关简单,就是拾取金币搬运货物,攒足金币升级建筑。在这过程当中,咱们还能够学习国家当前政策。python

因为游戏玩法很简单,这让我萌发了自动化测试(开挂)的念头。git

项目地址:github.com/Jiahonzheng… 。 演示视频:www.bilibili.com/video/av692…github

MuMu 模拟器

咱们使用网易游戏推出的 MuMu 模拟器,进行自动化测试。安装过程很简单的,这里也就不提了。这里的核心要点是 开启 USB 调试选项adb 调试地址(127.0.0.1:7555)算法

BTW,因为我使用的手机是 SONY Xperia Z5 Premium ,故我将模拟器的分辨率设置为 1920*1080 ,项目所用到的素材也都是基于此分辨率制做的。bash

UIAutomator2

咱们使用 UIAutomator2 做为自动化测试工具,其工做流程大体以下:机器学习

  • 在移动设备上安装 ATX 守护进程,其会启动 UIAutomator2 服务(默认端口:7912)进行监听。
  • 咱们在PC上编写测试脚本,发送脚本至到移动设备的server端。
  • 移动设备经过 Wi-Fi 或 USB 接收到 PC 发送的脚本,执行制定的操做。

咱们执行下列命令完成 UIAutomator2 的安装和初始化工做(请务必确保已完成 adb 链接)。ide

# 安装依赖
python -m pip install uiautomator2

# 安装 ATX 应用
python -m uiautomator2 init
复制代码

在安装完 ATX 应用后,咱们点击应用内部的**”启动 UIAutomator2“**,确保服务已开启。随后,咱们编写并执行如下代码,便可生成屏幕快照。函数

import uiautomator2 as u2

d = u2.connect("127.0.0.1:7555")
d.screenshot("Game.jpg")
复制代码

滑屏拾币

在游戏中,每栋建筑均可产生必定数量的金币,咱们可在建筑物间滑动,来拾取金币。为实现滑屏拾币的自动化,咱们可调用 device.swipe 方法,这是 uiautomator2 提供的实现触摸滑动的函数,咱们须要为其传入起始点屏幕坐标和终止点屏幕坐标。工具

便于开发,咱们为每块地创建对应的编号,具体以下图所示。学习

编号与屏幕位置的对应关系以下。请注意,这是 1920*1080 尺寸下的屏幕位置。

@staticmethod
def _get_position(key):
    """ 获取指定建筑的屏幕位置。 """
    positions = {
        1: (294, 1184),
        2: (551, 1061),
        3: (807, 961),
        4: (275, 935),
        5: (535, 810),
        6: (799, 687),
        7: (304, 681),
        8: (541, 568),
        9: (787, 447)
    }
    return positions.get(key)
复制代码

咱们的滑屏拾币的策略很简单:分 3 次滑屏,第 1 次是 1 - 3 号建筑,第 2 次是 4 - 6 号建筑,第 3 次是 7 - 9 号建筑。

def _swipe(self):
    """ 滑动屏幕,收割金币。 """
    for i in range(3):
        # 横向滑动,共 3 次。
        sx, sy = self._get_position(i * 3 + 1)
        ex, ey = self._get_position(i * 3 + 3)
        self.d.swipe(sx, sy, ex, ey)
复制代码

OpenCV

目测该游戏是使用 Unity 实现,咱们在 weditor 里没法获取足够的 Hierarchy 信息,所以为了实现搬运货物的功能,咱们只能选择图像识别的策略:咱们获取游戏的屏幕快照,而后判断其中是否含有货物,如有则搬运至目的建筑。咱们可使用 OpenCV 的模版匹配功能实现此需求。

首先,咱们须要安装 OpenCV 依赖。

python -m pip install opencv
复制代码

咱们先对 cv2.matchTemplate 进行一次简单的测试,看它的效果如何。

import cv2
# 读取快照
screen = cv2.imread('Game.jpg')
# 读取货物图片
template = cv2.imread('targets/Sofa.jpg')
# 获取货物图片的长宽信息
th, tw = template.shape[:2]
# 调用 OpenCV 的模版匹配方法
res = cv2.matchTemplate(screen, template, cv2.TM_SQDIFF_NORMED)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)

# min_val 可用来判断是否检测到货物

# 矩形左上角坐标
tl = min_loc
# 矩形右下角坐标
br = (tl[0] + tw, tl[1] + th)

cv2.rectangle(screen, tl, br, (0, 0, 255), 2)
cv2.imwrite('Result.jpg', screen)
复制代码

执行上述代码,咱们便可在快照中标记出 Sofa 的位置(红框圈住的物体),这代表此方法是能够 work 的。

搬运货物

咱们封装了 UIMatcher 类,用于探测物体是否存在,并采起相应举动。咱们根据 min_val 的值,咱们来判断是否已检测到货物。

# 阈值判断。
if min_val > 0.15:
    return None
复制代码

咱们在 _match_target 函数中,实现了搬运货物的功能。因为 OpenCV 的模版匹配也有“智障”的时候,咱们采用了冗余搬运的方式。

def _match_target(self, target: TargetType):
    """ 探测货物,并搬运货物。 """
    # 获取当前屏幕快照
    screen = self.d.screenshot(format="opencv")

    # 因为 OpenCV 的模板匹配有时会智障,故咱们探测次数实现冗余。
    counter = 6
    while counter != 0:
        counter = counter - 1

        # 使用 OpenCV 探测货物。
        result = UIMatcher.match(screen, target)

        # 若无探测到,终止对该货物的探测。
        # 实现冗余的缘由:返回的货物屏幕位置与实际位置存在误差,致使移动失效
        if result is None:
            break

        sx, sy = result
        # 获取货物目的地的屏幕位置。
        ex, ey = self._get_target_position(target)

        # 搬运货物。
        self.d.swipe(sx, sy, ex, ey)
复制代码

组装程序

到这里,咱们已经把两个核心功能(滑屏拾币搬运货物)都实现了。如今,咱们须要对其组装。咱们的方式很简单粗暴,在 Automator 类的 start 方法中,咱们在循环里,周而复始地进行搬运货物滑屏拾币的任务。

def start(self):
    """ 启动脚本,请确保已进入游戏页面。 """
    while True:
        # 判断是否出现货物。
        for target in TargetType:
            self._match_target(target)

        # 简单粗暴的方式,处理 “XX之光” 的荣誉显示。
        # 固然,也可使用图像探测的模式。
        self.d.click(550, 1650)

        # 滑动屏幕,收割金币。
        self._swipe()
复制代码

结语

在这篇博客中,咱们使用了 MuMu 模拟器、UIAutomator2 和 OpenCV 实现了《家国梦》游戏的自动化测试,解决了两个“核心“玩法的自动化模拟问题:滑屏拾币搬运货物 。固然,咱们的实现是存在不少能够改进的地方,如货物的探测算法,或许咱们可使用机器学习来解决这个 Object Detection 的问题,哈哈哈。

相关文章
相关标签/搜索