アズールレーンの周回操作をPythonで自動化したい その1

次 その2

注:アプリをandroidエミュレータ(Nox)上で動作させます。利用は自己責任でお願いします。

Noxのインストール、使用方法についてはNoxPlayer公式サイトを参照

記事を書いた経緯

スマホゲーム「アズールレーン」はオート戦闘機能はあるものの、
周回自体はかなりめんどくさい1

アズールレーン赤城加賀自働周回マシーンという記事を見つけたが自分はpythonしか扱えないので途方に暮れる。
どーにかならんもんかなと調べてたら、pythonでも画像を使った自動操作が行えることを知る。
PyAutoGuiで繰り返し作業をPythonにやらせよう

じゃあPyAutoGuiで周回操作を自動化してみようと頑張ってみた。

要約:何百連してもタルテュがガチャでゲットできないので、即席の周回方法を考えよう。

できること

下記動画参照(無音+1.5倍速)
紹介動画

必要な物

  • androidエミュレータ(本記事ではNoxを使用。アズレンが動けば何でもいい)
  • アズレンのアプリ(エミュレータ上にインストールしておく)
  • python3(本記事ではPython 3.8.2を使用。コードの書き換えが必要だが多分python2でも動く)

使用するモジュール

  • PyAutoGui(GUI自動化モジュール)
  • opencv_python(画像処理モジュール)
  • time(時間モジュール)

pipでインストール。
timeはpythonにデフォルトでインストールされている。

概略

  1. クリックしたい画像(敵画像、出撃ボタン等)を集める
  2. 「ゲーム画面に画像と一致する部分が見つかった場合、そこをクリックする」操作をループ処理でゴリ押す

画像の収集

まずは手動でゲームを進めて、クリック操作が必要な部分を探し、画像を集める。
windows10の場合 shift+Win+S のショートカットを使ってスクショを取ると便利。
アズールレーン赤城加賀自働周回マシーン
の画像のマッチングについての内容が参考になった。
043401.png 駄目な例

image23.png  良い例

画像名をすべて連番にすると途中で画像を付け足す際にリネームが面倒だったので
出撃前(1-10)
戦闘後(11-20)
敵画像(21-)
と区切って名前を割り振ることにした。

一例
061430.png

PyAutoGuiで自動操作

敵艦の画像(image23)でマッチングする場合

# 画面にimage8と同じ画像(グレースケールで認識、信頼度90%)がある場合
if pyautogui.locateCenterOnScreen("./image23.png", grayscale=True, confidence=0.9):
    # 座標を設定
    x,y = pyautogui.locateCenterOnScreen("./image23.png", grayscale=True, confidence=0.9)
    # 設定した座標をクリック
    pyautogui.click(x,y)

これで敵艦発見→クリックを自動化できる。

出撃ボタンや確定ボタンにも同様の処理を施してループ処理を行えば、出撃→ステージクリアまでを全て自動化できる

完成したスクリプト(automatic_operation.py)

対象ステージ イベント海域「帰路は海色の陰りへと」SP3
周回モード:ON
出撃確認skip:ON

このステージでは偵察艦隊、主力艦隊、ボスしか出現しないので、
敵画像はその3種+オールマイティ(レベル表記部分)を指定。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# automatic_operation.py
#
import pyautogui
import time

def main():
    print("開始")
    while True:
        # 出撃まで操作(image1~10)
        # ステージ選択画面(10秒停止。この猶予を使って再度周回するようマクロを組んだりスクリプトを終了させたりする)
        if pyautogui.locateCenterOnScreen("./image1.png", grayscale=True, confidence=0.9):
            print("ステージ選択")
            time.sleep(10)
        # 出撃ボタン(マップ決定)
        elif pyautogui.locateCenterOnScreen("./image2.png", grayscale=True, confidence=0.9):
            print("出撃")
            x,y = pyautogui.locateCenterOnScreen("./image2.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 出撃ボタン(編成決定)
        elif pyautogui.locateCenterOnScreen("./image3.png", grayscale=True, confidence=0.9):
            print("出撃(編成決定)")
            x,y = pyautogui.locateCenterOnScreen("./image3.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
            time.sleep(3)

        # バトル後操作(image11-20)
        # 敵艦隊を撃破
        elif pyautogui.locateCenterOnScreen("./image11.png", grayscale=True, confidence=0.9):
            print("撃破")
            x,y = pyautogui.locateCenterOnScreen("./image11.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # アイテム入手
        elif pyautogui.locateCenterOnScreen("./image12.png", grayscale=True, confidence=0.9):
            print("アイテム入手")
            x,y = pyautogui.locateCenterOnScreen("./image12.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 確定
        elif pyautogui.locateCenterOnScreen("./image14.png", grayscale=True, confidence=0.9):
            print("確定")
            x,y = pyautogui.locateCenterOnScreen("./image14.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 勝利画面(潜水艦出撃時の「確定」ボタンが出ない場合)
        elif pyautogui.locateCenterOnScreen("./image13.png", grayscale=True, confidence=0.9):
            print("勝利(潜水艦使用)")
            x,y = pyautogui.locateCenterOnScreen("./image13.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)


        #敵(21-)
        # ボス
        elif pyautogui.locateCenterOnScreen("./image21.png", grayscale=True, confidence=0.9):
            print("ボス")
            x,y = pyautogui.locateCenterOnScreen("./image21.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 偵察艦隊
        elif pyautogui.locateCenterOnScreen("./image22.png", grayscale=True, confidence=0.9):
            print("偵察")
            x,y = pyautogui.locateCenterOnScreen("./image22.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 主力艦隊
        elif pyautogui.locateCenterOnScreen("./image23.png", grayscale=True, confidence=0.9):
            print("主力")
            x,y = pyautogui.locateCenterOnScreen("./image23.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)
        # 敵発見(艦種不明)
        elif pyautogui.locateCenterOnScreen("./image24.png", grayscale=True, confidence=0.9):
            print("艦種不明")
            x,y = pyautogui.locateCenterOnScreen("./image24.png", grayscale=True, confidence=0.9)
            pyautogui.click(x,y)

        # wait
        else:
            print("wait")
            time.sleep(3)
            print("再検索")

if '__main__' == __name__:
    main()

このpyファイルをコマンドラインから実行する。

python3 automatic_operation.py

注意
実行中は他の操作ができなくなる。
無限ループするのでコマンドラインをすぐにアクティブにできないと、望む操作の前にマウスが勝手に移動して制御不能に陥る。
スクリプト実行時には上記の動画のように、コマンドラインとエミュレータの画面が両方見える状態にすることを推奨。
ログがwaitばかりになった場合はctrl+cでスクリプトを強制終了させてマッチング対象の画像を作り直す。
何なら様々な敵画像素材を作って処理精度を上げるのもアリ(ただし処理は遅くなる)。

課題

  • 地形や自キャラが敵に被るとマッチングが失敗する。
    055956.png ボスアイコンを認識させていたので、この状態だと処理が止まる。

  • クリックした敵艦への航路が遮断されていると詰む。

  • 時々座標の取得に失敗してTypeError(座標が取れないとx,yがNoneになる)で処理が止まる。

  • ドックがいっぱいになると出撃できない。

  • 無限ループが仕様なのが気に入らない。

  • スクリプト組んでる間に周回が終わってタルテュがゲットできてしまった。

対処は簡単そうなので次回以降段階的に改善。


  1. 戦闘以外(出撃→接敵→戦闘→勝利→接敵→...)は自動化できない。マップ上に敵が出現する位置もランダムなので、マクロで一括自動化というのも不可能。 

Chronona
Bioinformaticsを勉強中。 気晴らしに研究用以外のスクリプトも書いてます。
ユーザー登録して、Qiitaをもっと便利に使ってみませんか。
  1. あなたにマッチした記事をお届けします
    ユーザーやタグをフォローすることで、あなたが興味を持つ技術分野の情報をまとめてキャッチアップできます
  2. 便利な情報をあとで効率的に読み返せます
    気に入った記事を「ストック」することで、あとからすぐに検索できます
コメント
この記事にコメントはありません。
あなたもコメントしてみませんか :)
すでにアカウントを持っている方は
ユーザーは見つかりませんでした