Guias
Macro BlueStacks com reconhecimento de imagem e loops
Monte uma macro BlueStacks com reconhecimento de imagem: capture um template no Asset Lab, ache-o no BlueStacks ou LDPlayer e repita até um estado aparecer.
- Windows
- Mac
- Emulador
- Dispositivo na nuvem
- Celular
- Studio
- SDK Python
Nesta página
- Por que um gravador não consegue ramificar
- Antes de começar
- Capturar um template no Asset Lab
- Escolha a chamada certa
- Restrinja a busca com search_region
- Ajuste o limiar
- Trate pop-ups com find_any_object
- Um LDPlayer macro loop que espera por um estado
- Uma macro BlueStacks completa com reconhecimento de imagem
- Solução de problemas
- O template nunca corresponde
- Corresponde à coisa errada
- Funciona em uma instância, falha em outra
Uma macro BlueStacks ou LDPlayer com reconhecimento de imagem olha para a tela antes de agir. Ela toca em um botão porque o botão está lá, fecha um pop-up porque o pop-up apareceu e para quando a mensagem de “sem energia” surge. Este guia monta uma no Macro Automation Studio (MAS) no BlueStacks ou no LDPlayer, do primeiro recorte de template até um loop que espera por um estado. Ele é para quem já não cabe no gravador embutido do emulador.
Por que um gravador não consegue ramificar
O gravador de macros do BlueStacks ou do LDPlayer guarda toques e tempos e os repete. Ele nunca olha para a tela. Não consegue perceber que um pop-up cobriu o botão, que a tela de carregamento demorou mais hoje ou que o contador chegou a zero. Toda macro gravada é uma linha reta.
Uma macro do MAS é um script Python. Cada chamada de mas.find_object tira uma captura de tela e procura nela uma imagem template com template matching do OpenCV. Quando a melhor correspondência atinge o limiar (threshold=0.8 por padrão), a chamada retorna o centro dela. Caso contrário, retorna None. Esse único if é o que permite a uma macro ramificar, esperar, tentar de novo e parar.
Antes de começar
- O MAS está instalado e você fez login com o teste ou um plano. O teste começa com o download gratuito; veja Instalar o MAS.
- O BlueStacks ou o LDPlayer está aberto com o ADB ativado e adicionado como dispositivo. Veja o guia do BlueStacks ou do LDPlayer.
- O emulador usa uma resolução fixa que você vai manter. Os guias usam 540x960 em retrato a 240 DPI como base.
- Um projeto Baseado em código está aberto no Code Editor. Veja Primeiros passos.
Capturar um template no Asset Lab
- Leve o app até a tela com o botão que você quer encontrar.
- No Code Editor, abra o painel Assets e clique em Abrir o Asset Helper. O Asset Lab abre com a tela ao vivo do seu dispositivo.
- Recorte um retângulo justo em volta do botão e salve. O recorte vai para a sua Biblioteca de imagens e recebe um ID numérico.
- Repita para todo estado que a macro precisa reconhecer: o botão de fechar do pop-up, o botão de confirmar, a mensagem de “concluído”.
- No painel Assets, clique em Copiar ID em cada imagem e declare-as no topo do seu script.
import mas
images = mas.images({
"play_button": 201,
"close_popup": 202,
"out_of_energy": 203,
})mas.images dá a cada ID um nome legível e diz ao empacotador quais imagens incluir quando você publica. Os templates podem ser jpg, png, gif ou webp, com até 10 MB cada. Veja Asset Lab.
Escolha a chamada certa
| Chamada | Use quando | Retorna |
|---|---|---|
find_object(image) | Você quer uma única olhada na tela agora | ObjectMatch ou None |
find_object_retry(image, total_tries=3, time_sleep=2.0) | A coisa pode demorar um pouco para aparecer | ObjectMatch ou None depois da última tentativa |
find_any_object([a, b, c]) | Vários templates servem: variantes de pop-up, dois temas | A primeira correspondência, com matched_template_id |
find_objects(image, max_matches=10) | O mesmo ícone aparece várias vezes e você quer todas | Uma lista ordenada por confiança |
find_object_retry é a primitiva de espera da casa: ela chama find_object até total_tries vezes com uma pausa fixa de time_sleep entre as tentativas que falharam e nunca dorme depois da última. Todo outro argumento nomeado (threshold, search_region, screenshot) é repassado a find_object. find_any_object_retry faz o mesmo sobre uma lista. Prefira essas a wait_for_object, que é mantida para macros antigas.
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")Um ObjectMatch tem x, y, center e matched_template_id. Ele não carrega uma pontuação, então ajuste o limiar na chamada em vez de ler uma confiança depois.
Restrinja a busca com search_region
O template matching desliza o template sobre a captura de tela inteira. Uma Region limita o deslize a um retângulo, o que é mais rápido e evita sósias em outras partes da tela. As coordenadas são pixels a partir do canto superior esquerdo.
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)Use uma região sempre que souber onde o elemento vive: a barra superior para contadores, a parte de baixo para botões de ação, o centro para diálogos. Leia a região no Asset Lab; o seletor de pontos mostra as coordenadas em pixels na tela ao vivo.
Ajuste o limiar
threshold vai de 0.0 a 1.0 e o padrão é 0.8. A correspondência precisa atingi-lo para contar.
- Baixe para 0.7 quando um template correto continua falhando por causa de anti-aliasing, uma pequena mudança de escala ou um efeito de brilho no botão.
- Suba para 0.9 quando um template corresponde ao lugar errado, por exemplo dois ícones parecidos em sequência ou um botão que também aparece esmaecido.
- Recorte de novo antes de descer de 0.7. Um limiar tão baixo aceita quase qualquer coisa da mesma cor.
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 glowTrate pop-ups com find_any_object
Pop-ups são o motivo pelo qual macros gravadas quebram. Dê à macro uma função que conhece todos os pop-ups e chame-a no topo de cada iteração do loop.
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 recebe uma lista e retorna a primeira correspondência. search_strategy="best_match" escolhe a maior pontuação da lista em vez disso, e "priority_order" tenta os templates na ordem em que você os listou. Retornar True permite ao loop fazer continue, então a próxima iteração olha para uma tela limpa.
Um LDPlayer macro loop que espera por um estado
Esperar é um loop com um prazo. find_object_retry cobre esperas curtas; para uma tela de carregamento que pode levar um minuto, escreva o loop você mesmo para registrar o progresso e desistir de forma limpa.
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() conta segundos e nunca pula quando o relógio muda, o que o torna o timer certo para um prazo. Toda espera precisa terminar: retorne None e deixe quem chamou decidir se para a execução.
Uma macro BlueStacks completa com reconhecimento de imagem
O script abre uma tela, limpa pop-ups, toca em um botão enquanto ele está ativo e para quando o template “sem energia” aparece ou o limite de tempo acaba. Troque os IDs de imagem pelos da sua Biblioteca de imagens.
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()Rode com Executar (F5) no Code Editor e acompanhe o console. Quando um template falhar, corrija o recorte primeiro e o limiar depois.
Solução de problemas
O template nunca corresponde
O recorte foi feito em uma resolução ou DPI diferente daquela em que o dispositivo roda agora, o recorte inclui fundo que mudou, ou o elemento é animado. Confira as configurações de tela do emulador contra as da captura, recorte mais justo e tente threshold=0.7. Se o elemento tem várias aparências, capture cada uma e use find_any_object. Um mas.ImageNotFoundError significa que o ID não está na sua Biblioteca de imagens; copie-o de novo no painel Assets.
Corresponde à coisa errada
O template é genérico: uma seta simples, um quadrado de uma cor só, uma palavra que aparece duas vezes. Recorte algo único ao lado, suba o limiar para 0.9 ou passe uma search_region para a busca ficar onde o elemento vive. find_objects mostra todo lugar em que o template pontua acima do limiar, o que deixa o sósia fácil de achar.
Funciona em uma instância, falha em outra
A segunda instância do emulador roda em outra resolução ou DPI. O template matching é baseado em pixels, então um template capturado a 540x960 não corresponde a 720x1280 nem a um DPI diferente. Coloque toda instância nas mesmas configurações de tela e reinicie. Em um dispositivo na nuvem, crie o dispositivo com o mesmo preset de tela da captura. Se as instâncias precisam ser diferentes, capture um conjunto de templates por resolução e escolha-o com mas.get_screen_size().
Nenhuma ferramenta de automação é 100% livre de riscos, por isso automatize com responsabilidade e a seu próprio critério.
Próximos passos
Páginas relacionadas
Obrigado. Se algo estiver errado, conte para a gente no Discord.
Dúvidas? Pergunte no Discord