ガイド
BlueStacks マクロの画像認識と LDPlayer のループ
画像認識を使った BlueStacks マクロの作り方: Asset Lab でテンプレートを切り出し、BlueStacks や LDPlayer で照合し、目的の状態が出るまでループします。
- Windows
- Mac
- エミュレータ
- クラウド端末
- スマホ
- Studio
- Python SDK
このページの内容
BlueStacks や LDPlayer の画像認識マクロは、動く前に画面を見ます。ボタンがそこにあるからタップし、ポップアップが出たから閉じ、「エネルギー切れ」のメッセージが表示されたら止まります。このガイドでは、Macro Automation Studio (MAS) で BlueStacks か LDPlayer 上に、最初のテンプレートの切り出しから、状態を待つループまでを作ります。エミュレータ内蔵のレコーダーでは物足りなくなった方向けです。
レコーダーが分岐できない理由
BlueStacks や LDPlayer のマクロレコーダーは、タップとタイミングを保存して再生します。画面はまったく見ません。ポップアップがボタンを覆ったこと、今日は読み込み画面が長かったこと、カウンターがゼロになったことを判断できません。記録されたマクロはすべて一本道です。
MAS のマクロは Python スクリプトです。各 mas.find_object 呼び出しはスクリーンショットを撮り、OpenCV のテンプレートマッチングでその中からテンプレート画像を探します。最良の一致がしきい値 (既定は threshold=0.8) に達すると、呼び出しはその中心を返します。そうでなければ None を返します。この 1 つの if が、マクロに分岐、待機、リトライ、停止をさせるものです。
始める前に
- MAS がインストール済みで、トライアルかプランでサインインしていること。トライアルは 無料ダウンロード から始まります。MAS のインストール を参照してください。
- BlueStacks か LDPlayer が ADB を有効にして動いており、デバイスとして追加されていること。BlueStacks か LDPlayer のガイドを参照してください。
- エミュレータが、今後も変えない固定の解像度を使っていること。ガイドは縦向きの 540x960、240 DPI を基準にしています。
- コードベースのプロジェクトが Code Editor で開いていること。はじめに を参照してください。
Asset Lab でテンプレートを取り込む
- アプリを、見つけたいボタンのある画面にします。
- Code Editor で アセット パネルを開き、Asset Helper を開く をクリックします。Asset Lab がデバイスのライブ画面で開きます。
- ボタンの周りをぴったり囲む長方形を切り出して保存します。切り抜きは画像ライブラリに入り、数値の ID を受け取ります。
- マクロが認識すべきすべての状態について繰り返します: ポップアップの閉じるボタン、確認ボタン、「完了」のメッセージ。
- アセット パネルで各画像の ID をコピー をクリックし、スクリプトの先頭で宣言します。
import mas
images = mas.images({
"play_button": 201,
"close_popup": 202,
"out_of_energy": 203,
})mas.images は各 ID に読みやすい名前を与え、公開時にどの画像を同梱するかをパッカーに伝えます。テンプレートは jpg、png、gif、webp で、1 枚 10 MB までです。Asset Lab を参照してください。
適切な呼び出しを選ぶ
| 呼び出し | 使う場面 | 戻り値 |
|---|---|---|
find_object(image) | 今の画面を 1 度だけ見たい | ObjectMatch または None |
find_object_retry(image, total_tries=3, time_sleep=2.0) | 対象が現れるまで少し時間がかかるかもしれない | ObjectMatch、または最後の試行後に None |
find_any_object([a, b, c]) | 複数のテンプレートのどれでもよい: ポップアップの変種、2 つのテーマ | 最初の一致、matched_template_id 付き |
find_objects(image, max_matches=10) | 同じアイコンが複数回現れ、すべて欲しい | 信頼度順に並んだリスト |
find_object_retry は標準の待機プリミティブです: find_object を最大 total_tries 回呼び、失敗した試行の間に一定の time_sleep を挟み、最後の試行の後には待ちません。他のすべてのキーワード (threshold、search_region、screenshot) は find_object に渡されます。find_any_object_retry はリストに対して同じことをします。古いマクロのために残されている wait_for_object より、これらを使ってください。
match = mas.find_object_retry(images.play_button, total_tries=5, time_sleep=1.5)
if match:
mas.click(match.x, match.y, delay_ms=1000)
else:
mas.log("Play button did not appear", level="warning")ObjectMatch には x、y、center、matched_template_id があります。スコアは持たないので、後から信頼度を読むのではなく、呼び出しでしきい値を調整してください。
search_region で検索を絞る
テンプレートマッチングは、スクリーンショット全体の上でテンプレートをスライドさせます。Region はスライドを長方形に限定するので、速くなり、画面の他の場所にある似たものを避けられます。座標は左上からのピクセルです。
from mas import Region
TOP_BAR = Region(x1=0, y1=0, x2=540, y2=120)
energy_icon = mas.find_object(images.energy_icon, search_region=TOP_BAR)要素の場所が分かっているときは常に領域を使ってください: カウンターなら上部バー、アクションボタンなら下部、ダイアログなら中央。領域は Asset Lab から読み取ります。座標ピッカーがライブ画面上のピクセル座標を示します。
しきい値を調整する
threshold は 0.0 から 1.0 で、既定は 0.8 です。一致とみなすには、これに達する必要があります。
- アンチエイリアス、わずかな拡大縮小、ボタンの発光効果のせいで正しいテンプレートを見失い続けるときは、0.7 に下げます。
- テンプレートが間違った場所に一致するとき、たとえば似たアイコンが 2 つ並んでいたり、グレーアウトしたボタンも現れたりするときは、0.9 に上げます。
- 0.7 より下げる前に切り出し直してください。そこまで低いしきい値は、同じ色のほぼ何でも受け入れます。
enabled = mas.find_object(images.claim_enabled, threshold=0.9) # strict: disabled and enabled look alike
glowing = mas.find_object(images.reward_icon, threshold=0.7) # lenient: the icon has a pulsing glowfind_any_object でポップアップを処理する
ポップアップは、記録されたマクロが壊れる原因です。すべてのポップアップを知っている関数を 1 つマクロに持たせ、各ループの先頭で呼びます。
POPUPS = [images.close_popup, images.confirm_button, images.later_button]
def clear_popups():
popup = mas.find_any_object(POPUPS)
if popup is None:
return False
mas.log(f"Closing popup {popup.matched_template_id}")
mas.click(popup.x, popup.y, delay_ms=800)
return Truefind_any_object はリストを受け取り、最初の一致を返します。search_strategy="best_match" は代わりにリスト全体で最高スコアを選び、"priority_order" は並べた順にテンプレートを試します。True を返すとループが continue するので、次の周回はきれいな画面を見ます。
状態を待つ LDPlayer マクロループ
待機とは、期限付きのループです。find_object_retry は短い待機をカバーします。1 分かかることのある読み込み画面には、進捗を記録してきれいに諦められるよう、ループを自分で書きます。
import time
def wait_for(image, timeout_s=60, every_s=2.0):
deadline = time.monotonic() + timeout_s
while time.monotonic() < deadline:
match = mas.find_object(image)
if match:
return match
time.sleep(every_s)
return Nonetime.monotonic() は秒を数え、時計が変わっても跳ばないため、期限に適したタイマーです。すべての待機には終わりが必要です: None を返し、実行を止めるかどうかは呼び出し側に決めさせます。
画像認識を使った完全な BlueStacks マクロ
このスクリプトは画面を開き、ポップアップを片付け、有効な間ボタンをタップし、「エネルギー切れ」のテンプレートが現れるか時間の予算が尽きたら止まります。画像 ID を画像ライブラリのものに置き換えてください。
import random
import sys
import time
import mas
from mas import Region
images = mas.images({
"play_button": 201,
"close_popup": 202,
"confirm_button": 203,
"out_of_energy": 204,
"home_screen": 205,
})
BOTTOM = Region(x1=0, y1=700, x2=540, y2=960)
TIME_BUDGET_S = 15 * 60
def clear_popups():
popup = mas.find_any_object([images.close_popup, images.confirm_button])
if popup is None:
return False
mas.click(popup.x, popup.y, delay_ms=800)
return True
def main():
home = mas.find_object_retry(images.home_screen, total_tries=10, time_sleep=3.0)
if home is None:
mas.log("Home screen never appeared", level="error")
sys.exit(2)
started = time.monotonic()
taps = 0
while time.monotonic() - started < TIME_BUDGET_S:
if clear_popups():
continue
if mas.find_object(images.out_of_energy):
mas.log("Out of energy, done")
break
button = mas.find_object_retry(images.play_button, total_tries=3, time_sleep=2.0, search_region=BOTTOM)
if button is None:
mas.log("Play button not found, looking again", level="warning")
continue
mas.click(button.x, button.y, delay_ms=1000)
taps += 1
time.sleep(random.uniform(0.8, 2.0))
mas.log(f"Finished after {taps} taps")
if __name__ == "__main__":
main()Code Editor で 実行 (F5) で実行し、コンソールを見ます。テンプレートを見失ったら、まず切り抜きを、次にしきい値を直します。
トラブルシューティング
テンプレートがまったく一致しない
切り抜きが、デバイスが今動いている解像度や DPI と違うもので撮られた、切り抜きに変化した背景が含まれている、または要素がアニメーションしています。エミュレータのディスプレイ設定を取り込み時のものと比べ、より小さく切り出し直し、threshold=0.7 を試してください。要素に複数の見た目があるなら、それぞれ取り込んで find_any_object を使います。mas.ImageNotFoundError は、その ID が画像ライブラリにまったくないことを意味します。アセット パネルからもう一度コピーしてください。
間違ったものに一致する
テンプレートが汎用的です: 単純な矢印、一色の四角、2 回出てくる単語。隣にある固有のものを切り出すか、しきい値を 0.9 に上げるか、要素のある場所に検索を留める search_region を渡します。find_objects はテンプレートがしきい値を超えたすべての場所を示すので、似たものを見つけやすくなります。
1 つのインスタンスでは動くが、別のインスタンスで失敗する
2 つ目のエミュレータインスタンスが別の解像度か DPI で動いています。テンプレートマッチングはピクセルベースなので、540x960 で取り込んだテンプレートは 720x1280 や別の DPI では一致しません。すべてのインスタンスを同じディスプレイ設定にして再起動してください。クラウドデバイスでは、取り込んだのと同じディスプレイプリセットでデバイスを作ります。インスタンスを変えざるを得ないなら、解像度ごとにテンプレートのセットを取り込み、mas.get_screen_size() で選びます。
100%リスクのない自動化ツールは存在しないため、自動化は責任を持って、ご自身の判断で行ってください。
次のステップ
関連ページ
ありがとうございます。誤りがあればDiscordでお知らせください。
質問がありますか? Discordで質問する