# Cómo crear un bot para juegos Android en MAS

> Cómo crear un bot para juegos Android en Macro Automation Studio: instala uno del Marketplace, pídeselo a MAS Agent o prográmalo en Python sobre BlueStacks.

Source: https://automationmacro.com/es/docs/make-a-bot-for-any-game (Guías, updated 2026-09-05)

Este tutorial muestra cómo crear un bot para juegos Android en Macro Automation Studio (MAS), desde un juego instalado hasta un bot que se ejecuta según un horario, en una cuenta o en varias. Un bot para juegos Android hecho con MAS trabaja desde la pantalla: encuentra botones por imagen, lee contadores con OCR y toca con tiempos humanizados. Está pensado para quien crea su primer bot en Windows o Mac.

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

## Antes de empezar

- MAS está instalado y has iniciado sesión con la prueba gratuita o un plan. Consulta [Instalar MAS](/docs/install).
- El juego se ejecuta en un dispositivo que MAS puede controlar: un emulador en este ordenador, un dispositivo en la nube o tu propio móvil. Consulta [Dispositivos](/docs/devices).
- El dispositivo está en un grupo de dispositivos y su tarjeta muestra Detenido, no Error. La página [Primeros pasos](/docs/getting-started) explica cómo añadir uno.
- Para la ruta de Python no necesitas nada más. MAS incluye su propio entorno de Python con el paquete `mas`.

## Cómo crear un bot para juegos Android: tres caminos

### Instalar uno del Marketplace

La vía más rápida cuando alguien ya ha creado un bot para tu juego.

1. Abre **Marketplace** y busca el juego.
2. Abre la publicación y haz clic en **Descargar**. El bot aparece en **Macros**.
3. En **Grupos de dispositivos**, abre tu grupo, elige el bot en el selector **Macro** del dispositivo y haz clic en **Iniciar**.

El recorrido completo con capturas está en [Cómo ejecutar una macro del Marketplace](/docs/run-macro-from-marketplace). Hay bots listos para [Whiteout Survival](/whiteout-survival-bot), [Kingshot](/kingshot-bot) y [Last Asylum: Plague](/last-asylum-plague-bot).

### Pedírselo a MAS Agent

La vía sin código para un juego sin publicación.

1. Abre **Agente** y elige el dispositivo.
2. Describe la rutina en una frase, incluido cuándo debe parar, y haz clic en **Generar**.
3. Responde cuando el agente pregunte. Se detiene y pregunta en lugar de adivinar.
4. Cuando la macro supere 3 ejecuciones de validación, haz clic en **Añadir a mis macros**.

Generar la macro consume créditos de IA; ejecutar la macro terminada no cuesta nada. El resultado es un proyecto de Python normal que puedes abrir y editar. Consulta [MAS Agent](/docs/agent).

### Programarlo en Python

Control total sobre cada decisión que toma el bot. El resto de esta página es este camino.

## Automatizar juegos Android con Python

### 1. Lista lo que el bot debe ver

Juega la rutina una vez a mano y anota cada pantalla por la que pasa. Es decir, el botón que pulsas, los avisos emergentes que interrumpen, el contador que muestra tu energía y el mensaje que significa que has terminado. Cada elemento se convierte en una imagen de plantilla o en una región OCR. Un bot que conoce su estado de parada nunca se ejecuta a ciegas.

### 2. Crea el proyecto

1. Abre **Macros** y haz clic en **Crear nuevo proyecto**.
2. Elige **Basado en código**, pon **Dispositivo objetivo** en móvil, nombra el proyecto y haz clic en **Crear proyecto**.
3. Abre el proyecto. El Code Editor muestra `src/app.py`, el archivo que MAS ejecuta.

### 3. Captura plantillas en Asset Lab

1. Inicia el juego en el dispositivo y ve a la pantalla con el botón.
2. En el Code Editor, abre el panel **Recursos** y haz clic en **Abrir Asset Helper**. Asset Lab se abre con la pantalla en directo.
3. Recorta un rectángulo ajustado alrededor del botón y guárdalo. Llega a tu biblioteca de imágenes con un ID numérico.
4. Repite con el botón de cerrar aviso, el botón de confirmar y el mensaje de "sin energía".
5. De vuelta en el panel **Recursos**, usa **Copiar ID** en cada imagen y pega los ID en `mas.images` al principio de tu script.

Mantén los recortes pequeños y distintivos. Una pantalla entera solo coincide con esa pantalla exacta; un botón coincide allí donde aparezca. Las plantillas pueden ser jpg, png, gif o webp, de hasta 10 MB cada una. La página [Asset Lab](/docs/asset-lab) cubre la herramienta en detalle.

### 4. Captura una región OCR

1. En Asset Lab, dibuja un recuadro alrededor del contador que quieres leer.
2. Ejecuta la prueba de OCR en directo y ajusta el recuadro hasta que los dígitos salgan limpios.
3. Copia las coordenadas a una `Region(x1, y1, x2, y2)` en tu script.

La [guía de OCR](/docs/guides/ocr-text-reading) explica los modos de segmentación y la conversión de color si el texto se lee mal.

### 5. Escribe el bucle

El bucle de abajo es la forma que comparten todos los bots de juego. Cada línea corresponde a una llamada del SDK:

- `find_object_retry` busca el botón hasta `total_tries=3` veces, con `time_sleep=2.0` segundos entre intentos, y devuelve `None` cuando nada coincide.
- `click(x, y, delay_ms=1000)` toca el centro de la coincidencia y espera un segundo a que el juego reaccione.
- `read_text(region, psm=7)` lee el contador como una sola línea.
- `time.sleep(random.uniform(0.8, 2.0))` añade una pausa humana entre rondas.
- `mas.save` y `mas.retrieve` conservan el contador de rondas, así que una ejecución detenida se reanuda donde lo dejó.
- Las condiciones de parada terminan el bucle. El ejemplo usa cinco: un número máximo de rondas, un presupuesto de tiempo, la plantilla de "sin energía", un contador bajo y demasiados fallos seguidos.

### 6. Ejecútalo y lee los logs

Elige el dispositivo en el Code Editor y haz clic en **Ejecutar** (<kbd>F5</kbd>). Cada línea de `mas.log` aparece en la consola de ejecución. **Detener** es <kbd>Mayús</kbd>+<kbd>F5</kbd>. Arregla una cosa cada vez: cuando una plantilla no se encuentra, recórtala de nuevo antes de tocar la lógica.

### 7. Prográmalo

1. Abre **Programador** y haz clic en **Crear nueva programación**.
2. Rellena el **Nombre**, elige la **Macro** y el **Puerto del emulador**, y fija la **Fecha** y la **Hora**.
3. Pon la **Recurrencia** en **Diaria** y haz clic en **Crear programación**.

La app debe seguir abierta; el programador se ejecuta dentro de ella. Consulta [Programador](/docs/scheduler) y [Bucles y programación](/docs/guides/loops-and-scheduling).

### 8. Ejecútalo en un grupo de dispositivos

Añade la instancia de emulador de cada cuenta como dispositivo en un mismo grupo, asigna el bot a cada dispositivo y haz clic en **Iniciar todos**. Los valores por dispositivo, como el nombre de la cuenta, vienen de un perfil de ajustes. Consulta [Farmeo multi instancia](/docs/guides/multi-instance).

## Un bot de ejemplo completo

Sustituye los ID de imagen y la región por los que capturaste. El script farmea un recurso hasta que la energía baja, se agota un presupuesto de tiempo o se completan treinta rondas, y sobrevive a un reinicio.

```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)` marca la ejecución como fallida, así que un webhook suscrito a `macro.failed` se entera. Una salida limpia informa de `macro.completed`. Consulta [Webhooks](/docs/webhooks).

## Consejos para que un bot sea estable

- **Resolución.** Las plantillas y las regiones pertenecen a la resolución y el DPI con los que las capturaste. Mantén todos los dispositivos que ejecutan el bot en el mismo ajuste; las guías de emuladores usan 540x960 en vertical a 240 DPI como línea base.
- **Higiene de plantillas.** Recorta solo el botón, nunca el fondo que lo rodea. Vuelve a recortar cuando una actualización del juego cambie el arte. Cuando un botón tiene dos aspectos, captura los dos y busca con `find_any_object`.
- **Condiciones de parada.** Todo bucle necesita al menos dos: un contador o un presupuesto de tiempo, y un estado de pantalla que signifique "hecho". Un bot sin ellas se ejecuta hasta que te des cuenta.
- **Ve despacio.** Una pausa de uno a dos segundos entre rondas cuesta poco y parece menos mecánica.
- **Registra la decisión, no el toque.** `mas.log("Energy 8, stopping")` te dice por qué terminó una ejecución; un log de cien clics, no.

## Qué puede salir mal

### El botón nunca se encuentra

El recorte es demasiado grande, el umbral es demasiado estricto para el arte o el dispositivo va a una resolución distinta de aquella con la que capturaste. Recorta más ajustado y luego prueba `threshold=0.7` en la llamada. La [guía de reconocimiento de imagen](/docs/guides/image-recognition-macros) tiene la lista completa de comprobaciones.

### El contador lee el número equivocado

La región incluye un icono vecino, o el texto es claro sobre fondo oscuro. Ajusta el recuadro en Asset Lab y pasa `color_conversion=ColorConversion.BLACK_WHITE`. La [guía de OCR](/docs/guides/ocr-text-reading) muestra cómo comprobar la confianza.

### El bot se para de inmediato el segundo día

El contador guardado ya está en el límite. El ejemplo limpia el almacenamiento cuando llega a `MAX_ROUNDS`; si cambiaste eso, llama a `mas.clear("farm_bot")` una vez desde un script de prueba.

### Los clics caen al lado del botón

La resolución o el DPI del emulador cambiaron después de la captura, o la ventana no está en vertical. Devuelve la pantalla del emulador al ajuste de la captura y vuelve a capturar lo que siga fallando.

Ninguna herramienta de automatización está libre de riesgos al 100 %, así que automatiza con responsabilidad y bajo tu propio criterio.
