# Cách làm tool auto game cho mọi game Android trong MAS

> Cách làm tool auto game cho bất kỳ game Android nào trong Macro Automation Studio: cài từ Marketplace, nhờ MAS Agent, hoặc tự viết bằng Python trên BlueStacks.

Source: https://automationmacro.com/vi/docs/make-a-bot-for-any-game (Hướng dẫn, updated 2026-09-05)

Hướng dẫn này chỉ cách làm tool auto game cho bất kỳ game Android nào trong Macro Automation Studio (MAS), từ một game đã cài đến một bot chạy theo lịch, trên một hoặc nhiều tài khoản. Bot MAS làm việc từ màn hình: chúng tìm nút bằng ảnh, đọc bộ đếm bằng OCR, và chạm với nhịp giống người, đó là cốt lõi của cách làm tool auto game bền. Trang dành cho người lần đầu làm bot trên Windows hoặc Mac.

<div class="doc-video" data-video="SDrdMIV49a8" data-title="How to make a bot for any game"></div>

## Trước khi bắt đầu

- MAS đã cài và bạn đã đăng nhập với bản dùng thử miễn phí hoặc gói. Xem [Cài đặt MAS](/docs/install).
- Game chạy trên thiết bị MAS điều khiển được: giả lập trên máy tính này, thiết bị cloud, hoặc điện thoại của bạn. Xem [Thiết bị](/docs/devices).
- Thiết bị nằm trong một nhóm thiết bị và thẻ của nó hiển thị Đã dừng, không phải Lỗi. Trang [Bắt đầu](/docs/getting-started) hướng dẫn thêm thiết bị.
- Với cách dùng Python, bạn không cần gì thêm. MAS mang theo môi trường Python riêng với gói `mas`.

## Cách làm tool auto game Android: ba cách

### Cài từ Marketplace

Cách nhanh nhất khi đã có người dựng bot cho game của bạn.

1. Mở **Marketplace** và tìm game.
2. Mở mục đó và nhấn **Tải xuống**. Bot xuất hiện trong **Macro**.
3. Trong **Nhóm thiết bị**, mở nhóm của bạn, chọn bot trong ô **Macro** của thiết bị và nhấn **Bắt đầu**.

Hướng dẫn đầy đủ kèm ảnh chụp là [Cách chạy macro từ Marketplace](/docs/run-macro-from-marketplace). Bot làm sẵn có cho [Whiteout Survival](/whiteout-survival-bot), [Kingshot](/kingshot-bot) và [Last Asylum: Plague](/last-asylum-plague-bot).

### Nhờ MAS Agent

Cách không cần viết mã cho game chưa có trên Marketplace.

1. Mở **Agent** và chọn thiết bị.
2. Mô tả thao tác trong một câu, gồm cả lúc nào nên dừng, và nhấn **Viết macro**.
3. Trả lời khi agent hỏi. Nó dừng lại hỏi thay vì đoán.
4. Khi macro vượt qua 3 lần chạy kiểm chứng, nhấn **Thêm vào Macro của tôi**.

Việc viết tiêu tốn credit AI; chạy macro đã hoàn thành thì không tốn gì. Kết quả là một dự án Python bình thường mà bạn mở và chỉnh được. Xem [MAS Agent](/docs/agent).

### Tự dựng bằng Python

Toàn quyền kiểm soát mọi quyết định của bot. Phần còn lại của trang này là cách này.

## Auto game Android bằng Python

### 1. Liệt kê những gì bot phải thấy

Chơi thao tác đó một lần bằng tay và ghi lại mọi màn hình nó đi qua. Đó là nút bạn nhấn, các popup chen ngang, bộ đếm hiển thị năng lượng, và thông báo cho biết bạn đã xong. Mỗi mục trở thành một ảnh mẫu hoặc một vùng OCR. Bot biết trạng thái dừng của mình thì không bao giờ chạy mù.

### 2. Tạo dự án

1. Mở **Macro** và nhấn **Tạo dự án mới**.
2. Chọn **Code-Based**, đặt **Thiết bị đích** là mobile, đặt tên dự án và nhấn **Tạo dự án**.
3. Mở dự án. Code Editor hiển thị `src/app.py`, tệp mà MAS chạy.

### 3. Chụp ảnh mẫu trong Asset Lab

1. Khởi động game trên thiết bị và đi tới màn hình có nút.
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.
3. Cắt một hình chữ nhật sát quanh nút và lưu. Nó vào Thư viện ảnh của bạn với một ID dạng số.
4. Lặp lại cho nút đóng popup, nút xác nhận và thông báo "hết năng lượng".
5. Quay lại bảng **Tài nguyên**, dùng **Sao chép ID** trên từng ảnh và dán các ID vào `mas.images` ở đầu mã của bạn.

Giữ mẩu cắt nhỏ và đặc trưng. Cả một màn hình chỉ khớp đúng màn hình đó; một nút thì khớp ở bất cứ đâu nút xuất hiện. Ảnh mẫu có thể là jpg, png, gif hoặc webp, tối đa 10 MB mỗi tệp. Trang [Asset Lab](/docs/asset-lab) nói chi tiết về công cụ.

### 4. Chụp vùng OCR

1. Trong Asset Lab, vẽ một khung quanh bộ đếm bạn muốn đọc.
2. Chạy kiểm thử OCR trực tiếp và thu hẹp khung cho đến khi các chữ số trả về sạch.
3. Chép tọa độ vào một `Region(x1, y1, x2, y2)` trong mã của bạn.

[Hướng dẫn OCR](/docs/guides/ocr-text-reading) giải thích các chế độ phân đoạn và chuyển đổi màu nếu chữ đọc kém.

### 5. Viết vòng lặp

Vòng lặp bên dưới là hình dạng mà mọi bot game đều có chung. Mỗi dòng ứng với một lời gọi SDK:

- `find_object_retry` tìm nút tối đa `total_tries=3` lần, cách nhau `time_sleep=2.0` giây, và trả về `None` khi không khớp gì.
- `click(x, y, delay_ms=1000)` chạm vào điểm giữa kết quả khớp và chờ một giây cho game phản ứng.
- `read_text(region, psm=7)` đọc bộ đếm như một dòng đơn.
- `time.sleep(random.uniform(0.8, 2.0))` thêm một khoảng nghỉ giống người giữa các lượt.
- `mas.save` và `mas.retrieve` giữ bộ đếm lượt, nên lần chạy bị dừng sẽ tiếp tục từ chỗ đã dừng.
- Điều kiện dừng kết thúc vòng lặp. Ví dụ dùng năm điều kiện: số lượt tối đa, ngân sách thời gian, ảnh mẫu "hết năng lượng", bộ đếm thấp, và quá nhiều lần trượt liên tiếp.

### 6. Chạy và đọc nhật ký

Chọn thiết bị trong Code Editor và nhấn **Chạy** (<kbd>F5</kbd>). Mọi dòng `mas.log` xuất hiện trong bảng điều khiển chạy. **Dừng** là <kbd>Shift</kbd>+<kbd>F5</kbd>. Sửa từng thứ một: khi không tìm thấy ảnh mẫu, cắt lại trước khi đụng đến logic.

### 7. Lập lịch

1. Mở **Lập lịch** và nhấn **Tạo lịch mới**.
2. Điền **Tên**, chọn **Macro** và **Cổng giả lập**, đặt **Ngày** và **Giờ**.
3. Đặt **Chu kỳ** là **Hằng ngày** và nhấn **Tạo lịch**.

Ứng dụng phải mở; bộ lập lịch chạy bên trong nó. Xem [Bộ lập lịch](/docs/scheduler) và [Vòng lặp và lập lịch](/docs/guides/loops-and-scheduling).

### 8. Chạy trên nhóm thiết bị

Thêm instance giả lập của mỗi tài khoản làm một thiết bị trong một nhóm, gán bot cho từng thiết bị và nhấn **Bắt đầu tất cả**. Giá trị riêng cho từng thiết bị như tên tài khoản đến từ hồ sơ cài đặt. Xem [Nuôi acc đa nhiệm](/docs/guides/multi-instance).

## Một bot ví dụ hoàn chỉnh

Thay ID ảnh và vùng bằng những gì bạn đã chụp. Mã này cày tài nguyên cho đến khi năng lượng xuống thấp, hết ngân sách thời gian, hoặc đủ ba mươi lượt, và nó sống sót qua khởi động lại.

```python
import random
import sys
import time

import mas
from mas import Region

images = mas.images({
    "attack_button": 101,
    "confirm_button": 102,
    "close_popup": 103,
    "out_of_energy": 104,
})

ENERGY_REGION = Region(x1=380, y1=20, x2=520, y2=60)
TASK = "farm_bot"
MAX_ROUNDS = 30
TIME_BUDGET_S = 20 * 60
MIN_ENERGY = 10


def pause(low=0.8, high=2.0):
    time.sleep(random.uniform(low, high))


def read_energy():
    result = mas.read_text(region=ENERGY_REGION, psm=7)
    digits = "".join(ch for ch in result.text if ch.isdigit())
    return int(digits) if digits else None


def clear_popups():
    popup = mas.find_any_object([images.close_popup, images.confirm_button])
    if popup:
        mas.click(popup.x, popup.y, delay_ms=800)
        return True
    return False


def main():
    rounds = mas.retrieve(TASK).get("rounds", 0)
    misses = 0
    started = time.monotonic()
    mas.log(f"Starting at round {rounds}")

    while rounds < MAX_ROUNDS:
        if time.monotonic() - started > TIME_BUDGET_S:
            mas.log("Time budget reached", level="warning")
            break
        if clear_popups():
            continue
        if mas.find_object(images.out_of_energy):
            mas.log("Out of energy, stopping")
            break
        energy = read_energy()
        if energy is not None and energy < MIN_ENERGY:
            mas.log(f"Energy {energy} is below {MIN_ENERGY}, stopping")
            break
        button = mas.find_object_retry(images.attack_button, total_tries=3, time_sleep=2.0)
        if button is None:
            misses += 1
            mas.log(f"Attack button not found ({misses})", level="warning")
            if misses >= 5:
                mas.log("Giving up after 5 misses", level="error")
                sys.exit(2)
            continue
        misses = 0
        mas.click(button.x, button.y, delay_ms=1000)
        pause()
        rounds += 1
        mas.save(TASK, {"rounds": rounds})
        mas.log(f"Round {rounds} of {MAX_ROUNDS}")

    if rounds >= MAX_ROUNDS:
        mas.clear(TASK)
    mas.log(f"Finished with {rounds} rounds")


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

`sys.exit(2)` đánh dấu lần chạy là thất bại, nên webhook đăng ký `macro.failed` sẽ biết. Thoát sạch báo `macro.completed`. Xem [Webhook](/docs/webhooks).

## Mẹo giữ bot ổn định

- **Độ phân giải.** Ảnh mẫu và vùng gắn với độ phân giải và DPI lúc bạn chụp. Giữ mọi thiết bị chạy bot ở cùng cài đặt; các hướng dẫn giả lập dùng 540x960 ở chế độ dọc và 240 DPI làm chuẩn cơ sở.
- **Vệ sinh ảnh mẫu.** Chỉ cắt nút, không bao giờ cắt nền quanh nó. Cắt lại sau khi bản cập nhật game đổi hình. Khi một nút có hai kiểu hiển thị, chụp cả hai và tìm bằng `find_any_object`.
- **Điều kiện dừng.** Mỗi vòng lặp cần ít nhất hai: một bộ đếm hoặc ngân sách thời gian, và một trạng thái màn hình nghĩa là "xong". Bot không có chúng sẽ chạy cho đến khi bạn để ý.
- **Chậm lại.** Khoảng nghỉ một đến hai giây giữa các lượt tốn rất ít mà trông ít máy móc hơn.
- **Ghi lại quyết định, không phải cú chạm.** `mas.log("Energy 8, stopping")` cho bạn biết vì sao lần chạy kết thúc; nhật ký của một trăm cú nhấp thì không.

## Điều gì có thể sai

### Không bao giờ tìm thấy nút

Mẩu cắt quá lớn, ngưỡng quá chặt với hình vẽ, hoặc thiết bị chạy ở độ phân giải khác với lúc bạn chụp. Cắt lại sát hơn, rồi thử `threshold=0.7` trên lời gọi. [Hướng dẫn nhận diện hình ảnh](/docs/guides/image-recognition-macros) có danh sách kiểm tra đầy đủ.

### Bộ đếm đọc sai số

Vùng bao gồm một biểu tượng bên cạnh, hoặc chữ sáng trên nền tối. Thu hẹp khung trong Asset Lab và truyền `color_conversion=ColorConversion.BLACK_WHITE`. [Hướng dẫn OCR](/docs/guides/ocr-text-reading) chỉ cách kiểm tra độ tin cậy.

### Bot dừng ngay lập tức vào ngày thứ hai

Bộ đếm đã lưu đang ở mức giới hạn. Ví dụ xóa bộ nhớ khi đạt `MAX_ROUNDS`; nếu bạn đã đổi điều đó, gọi `mas.clear("farm_bot")` một lần từ một đoạn mã nháp.

### Cú nhấp rơi cạnh nút

Độ phân giải hoặc DPI của giả lập đã đổi sau khi chụp, hoặc cửa sổ không ở chế độ dọc. Đặt lại màn hình giả lập về cài đặt lúc chụp và chụp lại bất cứ thứ gì vẫn trượt.

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.
