Buscar

Guías

Macro BlueStacks con reconocimiento de imagen y bucles

Crea una macro BlueStacks con reconocimiento de imagen: captura una plantilla en Asset Lab, búscala en BlueStacks o LDPlayer y repite hasta ver un estado.

  • Windows
  • Mac
  • Emulador
  • Dispositivo en la nube
  • Teléfono
  • Studio
  • SDK de Python
Principiante Actualizado 7 min de lectura
En esta página
  1. Por qué un grabador no puede ramificarse
  2. Antes de empezar
  3. Capturar una plantilla en Asset Lab
  4. Elegir la llamada adecuada
  5. Acotar la búsqueda con search_region
  6. Ajustar el umbral
  7. Gestionar avisos emergentes con find_any_object
  8. Un LDPlayer macro loop que espera a un estado
  9. Una macro BlueStacks completa con reconocimiento de imagen
  10. Solución de problemas
  11. La plantilla nunca coincide
  12. Coincide con lo que no debe
  13. Funciona en una instancia y falla en otra

Una macro BlueStacks con reconocimiento de imagen, o una de LDPlayer, mira la pantalla antes de actuar. Toca un botón porque el botón está ahí, cierra un aviso porque el aviso apareció y se detiene cuando aparece el mensaje de “sin energía”. Esta guía construye una macro BlueStacks con reconocimiento de imagen en Macro Automation Studio (MAS), también válida para LDPlayer, desde el primer recorte de plantilla hasta un bucle que espera a un estado. Está pensada para quien se ha quedado corto con el grabador integrado del emulador.

Por qué un grabador no puede ramificarse

El grabador de macros de BlueStacks o LDPlayer guarda toques y tiempos y los reproduce. Nunca mira la pantalla. No puede saber que un aviso tapó el botón, que la pantalla de carga tardó más hoy o que el contador llegó a cero. Toda macro grabada es una línea recta.

Una macro de MAS es un script de Python. Cada llamada a mas.find_object hace una captura y busca en ella una imagen de plantilla con la coincidencia de plantillas (template matching) de OpenCV. Cuando la mejor coincidencia alcanza el umbral (threshold=0.8 por defecto), la llamada devuelve su centro. Si no, devuelve None. Ese único if es lo que permite a una macro ramificarse, esperar, reintentar y parar.

Antes de empezar

  • MAS está instalado y con sesión iniciada con la prueba o un plan. La prueba empieza con la descarga gratuita; consulta Instalar MAS.
  • BlueStacks o LDPlayer está en marcha con ADB activado y añadido como dispositivo. Consulta la guía de BlueStacks o de LDPlayer.
  • El emulador usa una resolución fija que vas a mantener. Las guías usan 540x960 en vertical a 240 DPI como línea base.
  • Un proyecto basado en código está abierto en el Code Editor. Consulta Primeros pasos.

Capturar una plantilla en Asset Lab

  1. Lleva la app a la pantalla con el botón que quieres encontrar.
  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 de tu dispositivo.
  3. Recorta un rectángulo ajustado alrededor del botón y guárdalo. El recorte va a tu biblioteca de imágenes y recibe un ID numérico.
  4. Repite con cada estado que la macro deba reconocer: el botón de cerrar del aviso, el botón de confirmar, el mensaje de “hecho”.
  5. En el panel Recursos, haz clic en Copiar ID en cada imagen y decláralas al principio de tu script.
python
import mas

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

mas.images da a cada ID un nombre legible e indica al empaquetador qué imágenes incluir cuando publiques. Las plantillas pueden ser jpg, png, gif o webp, de hasta 10 MB cada una. Consulta Asset Lab.

Elegir la llamada adecuada

LlamadaÚsala cuandoDevuelve
find_object(image)Quieres una sola mirada a la pantalla ahora mismoObjectMatch o None
find_object_retry(image, total_tries=3, time_sleep=2.0)El elemento puede tardar un momento en aparecerObjectMatch o None tras el último intento
find_any_object([a, b, c])Valen varias plantillas: variantes de un aviso, dos temasLa primera coincidencia, con matched_template_id
find_objects(image, max_matches=10)El mismo icono aparece varias veces y las quieres todasUna lista ordenada por confianza

find_object_retry es la primitiva de espera de la casa: llama a find_object hasta total_tries veces con una pausa fija time_sleep entre intentos fallidos y nunca duerme después del último. Todos los demás argumentos con nombre (threshold, search_region, screenshot) se reenvían a find_object. find_any_object_retry hace lo mismo sobre una lista. Prefiere estas a wait_for_object, que se mantiene por las macros antiguas.

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

Un ObjectMatch tiene x, y, center y matched_template_id. No lleva puntuación, así que ajusta el umbral en la llamada en lugar de leer una confianza después.

Acotar la búsqueda con search_region

La coincidencia de plantillas desliza la plantilla por toda la captura. Una Region limita el barrido a un rectángulo, lo que es más rápido y evita parecidos en otras partes de la pantalla. Las coordenadas son píxeles desde la esquina superior izquierda.

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)

Usa una región siempre que sepas dónde vive el elemento: la barra superior para los contadores, la inferior para los botones de acción, el centro para los diálogos. Lee la región en Asset Lab; el selector de puntos muestra las coordenadas en píxeles sobre la pantalla en directo.

Ajustar el umbral

threshold va de 0.0 a 1.0 y por defecto es 0.8. La coincidencia debe alcanzarlo para contar.

  • Bájalo a 0.7 cuando una plantilla correcta sigue fallando por el suavizado, un ligero cambio de escala o un brillo en el botón.
  • Súbelo a 0.9 cuando una plantilla coincide en el sitio equivocado, por ejemplo dos iconos parecidos seguidos o un botón que también aparece en gris.
  • Vuelve a recortar antes de bajar de 0.7. Un umbral tan bajo acepta casi cualquier cosa del mismo color.
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

Gestionar avisos emergentes con find_any_object

Los avisos emergentes son el motivo por el que se rompen las macros grabadas. Dale a la macro una función que conozca todos los avisos y llámala al principio de cada pasada del bucle.

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 recibe una lista y devuelve la primera coincidencia. search_strategy="best_match" elige en cambio la puntuación más alta de la lista, y "priority_order" prueba las plantillas en el orden en que las listaste. Devolver True permite al bucle hacer continue, así que la siguiente pasada mira una pantalla limpia.

Un LDPlayer macro loop que espera a un estado

Esperar es un bucle con un plazo. find_object_retry cubre las esperas cortas; para una pantalla de carga que puede tardar un minuto, escribe el bucle tú mismo para registrar el progreso y rendirte limpiamente.

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() cuenta segundos y nunca salta cuando cambia el reloj, lo que lo convierte en el temporizador adecuado para un plazo. Toda espera debe terminar: devuelve None y deja que quien llama decida si detener la ejecución.

Una macro BlueStacks completa con reconocimiento de imagen

El script abre una pantalla, cierra los avisos, toca un botón mientras está activo y se detiene cuando aparece la plantilla de “sin energía” o se agota el presupuesto de tiempo. Sustituye los ID de imagen por los de tu biblioteca de imágenes.

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

Ejecútalo con Ejecutar (F5) en el Code Editor y observa la consola. Cuando una plantilla falle, arregla primero el recorte y después el umbral.

Solución de problemas

La plantilla nunca coincide

El recorte se hizo con una resolución o un DPI distintos de los que usa ahora el dispositivo, el recorte incluye fondo que cambió, o el elemento está animado. Compara los ajustes de pantalla del emulador con los de la captura, recorta más ajustado y prueba threshold=0.7. Si el elemento tiene varios aspectos, captura cada uno y usa find_any_object. Un mas.ImageNotFoundError significa que el ID no está en tu biblioteca de imágenes; cópialo otra vez desde el panel Recursos.

Coincide con lo que no debe

La plantilla es genérica: una flecha simple, un cuadrado de un solo color, una palabra que aparece dos veces. Recorta algo único junto a ella, sube el umbral a 0.9 o pasa una search_region para que la búsqueda se quede donde vive el elemento. find_objects te muestra todos los sitios donde la plantilla supera el umbral, lo que hace fácil detectar el parecido.

Funciona en una instancia y falla en otra

La segunda instancia del emulador va a otra resolución u otro DPI. La coincidencia de plantillas se basa en píxeles, así que una plantilla capturada a 540x960 no coincide a 720x1280 ni con otro DPI. Pon todas las instancias con los mismos ajustes de pantalla y reinícialas. En un dispositivo en la nube, crea el dispositivo con el mismo preajuste de pantalla con el que capturaste. Si las instancias deben ser distintas, captura un juego de plantillas por resolución y elígelo con mas.get_screen_size().

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

Siguientes pasos

Páginas relacionadas

¿Te ha servido esta página?

¿Dudas? Pregunta en Discord