Tìm kiếm

Hướng dẫn

Macro nhận diện hình ảnh BlueStacks và vòng lặp LDPlayer

Dựng macro nhận diện hình ảnh cho BlueStacks: cắt ảnh mẫu trong Asset Lab, so khớp trên BlueStacks hoặc LDPlayer, và lặp cho đến khi một trạng thái xuất hiện.

  • Windows
  • Mac
  • Giả lập
  • Thiết bị đám mây
  • Điện thoại
  • Studio
  • Python SDK
Cơ bản Cập nhật 8 phút đọc
Trong trang này
  1. Vì sao trình ghi không rẽ nhánh được
  2. Trước khi bắt đầu
  3. Chụp ảnh mẫu trong Asset Lab
  4. Chọn đúng lời gọi
  5. Thu hẹp phạm vi tìm bằng search_region
  6. Chỉnh ngưỡng
  7. Xử lý popup bằng find_any_object
  8. LDPlayer macro loop chờ một trạng thái
  9. Macro nhận diện hình ảnh hoàn chỉnh trên BlueStacks
  10. Khắc phục sự cố
  11. Ảnh mẫu không bao giờ khớp
  12. Khớp nhầm thứ khác
  13. Chạy được trên một instance, trượt trên instance khác

Một macro nhận diện hình ảnh trên BlueStacks hoặc LDPlayer nhìn màn hình trước khi hành động. Macro nhận diện hình ảnh chạm vào nút vì nút đang ở đó, đóng popup vì popup vừa hiện, và dừng khi thông báo “hết năng lượng” xuất hiện. Hướng dẫn này dựng một macro như vậy trong Macro Automation Studio (MAS) trên BlueStacks hoặc LDPlayer, từ mẩu cắt ảnh mẫu đầu tiên đến vòng lặp chờ một trạng thái. Trang dành cho bất kỳ ai đã vượt quá khả năng của trình ghi tích hợp trong giả lập.

Vì sao trình ghi không rẽ nhánh được

Trình ghi macro trong BlueStacks hoặc LDPlayer lưu cú chạm và thời gian rồi phát lại. Nó không bao giờ nhìn màn hình. Nó không biết popup đã che nút, màn hình tải hôm nay lâu hơn, hay bộ đếm đã về 0. Mọi macro đã ghi đều là một đường thẳng.

Macro MAS là một đoạn mã Python. Mỗi lời gọi mas.find_object chụp một ảnh màn hình và tìm ảnh mẫu trong đó bằng so khớp mẫu OpenCV. Khi kết quả khớp tốt nhất đạt ngưỡng (threshold=0.8 theo mặc định), lời gọi trả về điểm giữa của nó. Nếu không, nó trả về None. Chính câu if đơn lẻ đó cho phép macro rẽ nhánh, chờ, thử lại và dừng.

Trước khi bắt đầu

  • MAS đã cài và đăng nhập với bản dùng thử hoặc gói. Bản dùng thử bắt đầu từ bản tải miễn phí; xem Cài đặt MAS.
  • BlueStacks hoặc LDPlayer đang chạy với ADB đã bật và đã thêm làm thiết bị. Xem hướng dẫn BlueStacks hoặc LDPlayer.
  • Giả lập dùng một độ phân giải cố định mà bạn sẽ giữ. Các hướng dẫn dùng 540x960 ở chế độ dọc và 240 DPI làm chuẩn cơ sở.
  • Một dự án Code-Based đang mở trong Code Editor. Xem Bắt đầu.

Chụp ảnh mẫu trong Asset Lab

  1. Đưa ứng dụng tới màn hình có nút bạn muốn tìm.
  2. Trong Code Editor, mở bảng Tài nguyên và nhấn Mở Asset Helper. Asset Lab mở với màn hình đang chạy của thiết bị.
  3. Cắt một hình chữ nhật sát quanh nút và lưu. Mẩu cắt vào Thư viện ảnh của bạn và nhận một ID dạng số.
  4. Lặp lại cho mọi trạng thái macro phải nhận ra: nút đóng popup, nút xác nhận, thông báo “xong”.
  5. Trong bảng Tài nguyên, nhấn Sao chép ID trên từng ảnh và khai báo chúng ở đầu mã của bạn.
python
import mas

images = mas.images({
    "play_button": 201,
    "close_popup": 202,
    "out_of_energy": 203,
})

mas.images cho mỗi ID một tên dễ đọc và cho trình đóng gói biết ảnh nào cần gói khi bạn đăng. Ảnh mẫu có thể là jpg, png, gif hoặc webp, tối đa 10 MB mỗi tệp. Xem Asset Lab.

Chọn đúng lời gọi

Lời gọiDùng khiTrả về
find_object(image)Bạn muốn nhìn màn hình đúng một lần ngay bây giờObjectMatch hoặc None
find_object_retry(image, total_tries=3, time_sleep=2.0)Thứ cần tìm có thể mất một lúc mới hiệnObjectMatch hoặc None sau lần thử cuối
find_any_object([a, b, c])Nhiều ảnh mẫu đều chấp nhận được: các biến thể popup, hai chủ đềKết quả khớp đầu tiên, kèm matched_template_id
find_objects(image, max_matches=10)Cùng một biểu tượng xuất hiện nhiều lần và bạn muốn tất cảDanh sách sắp theo độ tin cậy

find_object_retry là lời gọi chờ chuẩn của nhà: nó gọi find_object tối đa total_tries lần với khoảng nghỉ time_sleep cố định giữa các lần thất bại và không bao giờ ngủ sau lần cuối. Mọi tham số khác (threshold, search_region, screenshot) được chuyển tiếp tới find_object. find_any_object_retry làm tương tự trên một danh sách. Ưu tiên chúng hơn wait_for_object, vốn giữ lại cho các macro cũ.

python
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")

Một ObjectMatchx, y, centermatched_template_id. Nó không mang điểm số, nên hãy chỉnh ngưỡng trên lời gọi thay vì đọc độ tin cậy sau đó.

Thu hẹp phạm vi tìm bằng search_region

So khớp mẫu trượt ảnh mẫu trên toàn bộ ảnh chụp màn hình. Một Region giới hạn việc trượt vào một hình chữ nhật, nhanh hơn và tránh các thứ trông giống ở nơi khác trên màn hình. Tọa độ là pixel tính từ góc trên bên trái.

python
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)

Dùng vùng bất cứ khi nào bạn biết phần tử nằm ở đâu: thanh trên cùng cho bộ đếm, phía dưới cho nút hành động, giữa cho hộp thoại. Đọc vùng từ Asset Lab; bộ chọn điểm hiển thị tọa độ pixel trên màn hình đang chạy.

Chỉnh ngưỡng

threshold chạy từ 0.0 đến 1.0 và mặc định là 0.8. Kết quả khớp phải đạt mức đó mới được tính.

  • Hạ xuống 0.7 khi một ảnh mẫu đúng cứ trượt vì khử răng cưa, thay đổi tỷ lệ nhỏ, hoặc hiệu ứng phát sáng trên nút.
  • Nâng lên 0.9 khi ảnh mẫu khớp nhầm chỗ, ví dụ hai biểu tượng giống nhau nằm cạnh nhau hoặc một nút cũng xuất hiện ở dạng xám mờ.
  • Cắt lại trước khi xuống dưới 0.7. Ngưỡng thấp đến vậy chấp nhận gần như bất cứ thứ gì cùng màu.
python
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 glow

Xử lý popup bằng find_any_object

Popup là lý do macro đã ghi bị hỏng. Cho macro một hàm biết mọi popup và gọi nó ở đầu mỗi lượt lặp.

python
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 True

find_any_object nhận một danh sách và trả về kết quả khớp đầu tiên. search_strategy="best_match" thay vào đó chọn điểm cao nhất trong cả danh sách, và "priority_order" thử các ảnh mẫu theo thứ tự bạn liệt kê. Trả về True cho phép vòng lặp continue, nên lượt tiếp theo nhìn vào một màn hình sạch.

LDPlayer macro loop chờ một trạng thái

Chờ là một vòng lặp có hạn chót. find_object_retry bao các lần chờ ngắn; với màn hình tải có thể mất một phút, hãy tự viết vòng lặp để bạn ghi tiến độ và bỏ cuộc gọn gàng.

python
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 None

time.monotonic() đếm giây và không bao giờ nhảy khi đồng hồ đổi, nên nó là bộ đếm giờ đúng cho một hạn chót. Mọi lần chờ phải kết thúc: trả về None và để bên gọi quyết định có dừng lần chạy hay không.

Macro nhận diện hình ảnh hoàn chỉnh trên BlueStacks

Mã này mở một màn hình, dọn popup, chạm vào nút khi nút còn bật, và dừng khi ảnh mẫu “hết năng lượng” xuất hiện hoặc hết ngân sách thời gian. Thay ID ảnh bằng ID trong Thư viện ảnh của bạn.

python
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()

Chạy bằng Chạy (F5) trong Code Editor và theo dõi bảng điều khiển. Khi một ảnh mẫu trượt, sửa mẩu cắt trước và ngưỡng sau.

Khắc phục sự cố

Ảnh mẫu không bao giờ khớp

Mẩu cắt được chụp ở độ phân giải hoặc DPI khác với thiết bị đang chạy, mẩu cắt có nền đã thay đổi, hoặc phần tử có hoạt ảnh. Đối chiếu cài đặt màn hình của giả lập với lúc bạn chụp, cắt lại sát hơn, và thử threshold=0.7. Nếu phần tử có nhiều kiểu hiển thị, chụp từng kiểu và dùng find_any_object. mas.ImageNotFoundError nghĩa là ID hoàn toàn không có trong Thư viện ảnh của bạn; sao chép lại từ bảng Tài nguyên.

Khớp nhầm thứ khác

Ảnh mẫu quá chung chung: một mũi tên trơn, một ô vuông một màu, một từ xuất hiện hai lần. Cắt thứ gì đó độc nhất bên cạnh nó, nâng ngưỡng lên 0.9, hoặc truyền search_region để việc tìm ở yên chỗ phần tử nằm. find_objects cho bạn thấy mọi chỗ ảnh mẫu đạt trên ngưỡng, giúp dễ phát hiện thứ trông giống.

Chạy được trên một instance, trượt trên instance khác

Instance giả lập thứ hai chạy ở độ phân giải hoặc DPI khác. So khớp mẫu dựa trên pixel, nên ảnh mẫu chụp ở 540x960 không khớp ở 720x1280 hay ở DPI khác. Đặt mọi instance về cùng cài đặt màn hình và khởi động lại. Trên thiết bị cloud, tạo thiết bị với cùng preset màn hình bạn đã chụp. Nếu các instance buộc phải khác nhau, chụp một bộ ảnh mẫu cho mỗi độ phân giải và chọn bằng mas.get_screen_size().

Không có công cụ tự động hóa nào an toàn 100%, vì vậy hãy tự động hóa một cách có trách nhiệm và theo quyết định của riêng bạn.

Bước tiếp theo

Trang liên quan

Trang này có hữu ích không?

Có câu hỏi? Hỏi trên Discord