PyAutoGUIとOpenCV画像認識を使いクリッカーゲームのBOT作成

# Python PyAutoGUIとOpenCV画像認識を使いクリッカーゲームのBOT作成

やりたいこと自作のクリッカーゲームの自動化
※ サンプルではCookie Clicker の自動化を行った→ http://orteil.dashnet.org/cookieclicker/

1. クッキーを自動でクリック
2. 一定回数クリック後にCursurが購入可能かチェックし可能な場合、買う
3. 1〜2を繰り返し行う

##  PyAutoGUIとopencv-pythonをインストール

PyAutoGUIドキュメント

https://github.com/asweigart/pyautogui

opencv-pythonドキュメント

https://github.com/opencv/opencv-python

```
pip install pyautogui
pip install opencv-python
```

## クッキーを自動でクリック

Cookie Clicker ブラウザ画面

![スクリーンショット 2021-03-14 16.28.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/48a03529-0c07-98f2-b97f-550af63b8dc8.png)

絶対座標 200:400をクリック
クリック回数は0.5秒間隔で10回行う

```Python
import pyautogui


def click():
    pyautogui.click(x=200, y=400, clicks=10, interval=0.5, button='left')


if __name__ == "__main__":
    click()
```

## Cursurが購入可能かチェック

最初にCursurの画像を取得

```Python
def screenshot_cursor():
    screenshot = pyautogui.screenshot(region=(2226, 1242, 120, 120))
    screenshot.save("images/cursor.png")
```

購入可能時と購入不可能時の画像をそれぞれ取得

購入可能
![cursor_active.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/d913e426-f7bb-590f-a092-c88af7cfcf9e.png)

購入不可
![cursor_no.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59264/28f1f819-0a58-efa2-8e82-c4b6900cc9ae.png)

### 購入可能判定

２つ方法があった

**PyAutoGUIのlocateOnScreenを使う**
`pyautogui.locateOnScreen` を使う現在の画面に対象画像が存在する場合に座標が返る。
不一致はNULL

confidenceは一致率、今回は画像は同じで購入できない場合グレー画像かだけなので判定精度の調整が難しかった
0.9999で購入出来る場合は座標が返り、購入出来ない場合はNULLになった

```Python
def match_cursor_active():
    rerturn pyautogui.locateOnScreen("images/cursor_active.png", confidence=.9999)
```

**OpenCVのmatchTemplateを使う**
minVal, maxValで一致率が分かる
今回の画像の場合、購入できる画像は`1.0, 1.0`
購入できない場合は`0.9970715045928955, 0.9970715045928955` となった

```Python
def match_cv_cursor_active():
    tmp = cv2.imread("images/cursor.png")
    cursor_active = cv2.imread("images/cursor_active.png")

    # 画像マッチング処理
    result = cv2.matchTemplate(cursor_active, tmp, cv2.TM_CCORR_NORMED)
    minVal, maxVal, _, _ = cv2.minMaxLoc(result)

    if minVal < 1:
        return False

    return True
```

備考：どちらも微妙なのでもっといい方法があれば教えて欲しい
色味判定などがいいのかもしれない
ぶっちゃけ今回の処理の場合、無条件でCursorクリックでも良いのだが...

### クリックして購入

```Python
def click_cursor():
    pyautogui.click(x=1150, y=650, clicks=1, interval=0, button='left')


if __name__ == "__main__":
    p = match_cursor_active()
    if p:
        click_cursor()

```

## 全体のコード

クッキークリック10回を10回繰り返す処理にした

```Python
import time

import cv2
import pyautogui


def click():
    pyautogui.click(x=200, y=400, clicks=10, interval=0.5, button='left')


def click_cursor():
    pyautogui.click(x=1150, y=650, clicks=1, interval=0, button='left')


def screenshot_cursor():
    screenshot = pyautogui.screenshot(region=(2226, 1242, 120, 120))
    screenshot.save("images/cursor.png")


def match_cursor_active():
    return pyautogui.locateOnScreen("images/cursor_active.png", confidence=.9999)


def match_cv_cursor_active():
    tmp = cv2.imread("images/cursor.png")
    cursor_active = cv2.imread("images/cursor_active.png")

    # 画像マッチング処理
    result = cv2.matchTemplate(cursor_active, tmp, cv2.TM_CCORR_NORMED)
    minVal, maxVal, _, _ = cv2.minMaxLoc(result)

    if minVal < 1:
        return False

    return True


if __name__ == "__main__":

    max = 10

    for loop in range(max):
        print(f"ループ回数：{loop}")
        click()
        p = match_cursor_active()
        if p:
            click_cursor()
            time.sleep(1)
```

#### 実行動画

https://twitter.com/gakushi0130/status/1371022358404767744

---

以上、クリッカーゲーム攻略方法でした

いいね！と思ったら LGTM お願いします :clap::clap::clap:

【PR】プログラミング新聞リリースしました！ → https://pronichi.com
【PR】週末ハッカソンというイベントやってます！ → https://weekend-hackathon.toyscreation.jp/about/