《家國夢》遊戲自動化測試

《家國夢》是最近很火的一款不用氪金的手遊,在周圍同窗好友的慫恿下,我走上了「不歸路」。這遊戲玩法至關簡單,就是拾取金幣搬運貨物,攢足金幣升級建築。在這過程當中,咱們還能夠學習國家當前政策。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 的問題,哈哈哈。

相關文章
相關標籤/搜索