가이드
블루스택 이미지 인식 매크로 만들기와 LD플레이어 반복
Asset Lab에서 템플릿을 잘라 BlueStacks나 LDPlayer 화면에서 찾고, 원하는 상태가 나타날 때까지 반복하는 블루스택 이미지 인식 매크로를 만듭니다.
- Windows
- Mac
- 에뮬레이터
- 클라우드 기기
- 휴대폰
- 스튜디오
- Python SDK
이 페이지의 내용
블루스택 이미지 인식 매크로, 또는 LDPlayer용 이미지 인식 매크로는 행동하기 전에 화면을 봅니다. 버튼이 있기 때문에 버튼을 탭하고, 팝업이 나타났기 때문에 팝업을 닫고, “out of energy” 메시지가 뜨면 멈춥니다. 이 가이드는 Macro Automation Studio(MAS)에서 BlueStacks나 LDPlayer용 블루스택 이미지 인식 매크로를 첫 템플릿 자르기부터 상태를 기다리는 반복문까지 만듭니다. 에뮬레이터 내장 녹화기로는 부족해진 분을 위한 가이드입니다.
녹화기가 분기할 수 없는 이유
BlueStacks나 LDPlayer의 매크로 녹화기는 탭과 타이밍을 저장해 재생합니다. 화면을 보지 않습니다. 팝업이 버튼을 덮었는지, 오늘 로딩 화면이 더 오래 걸렸는지, 카운터가 0에 도달했는지 알 수 없습니다. 녹화된 매크로는 모두 일직선입니다.
MAS 매크로는 파이썬 스크립트입니다. 각 mas.find_object 호출이 스크린샷을 찍어 OpenCV 템플릿 매칭으로 템플릿 이미지를 찾습니다. 최고 일치가 임계값(기본 threshold=0.8)에 도달하면 중심을 반환하고, 아니면 None을 반환합니다. 그 if 하나가 매크로가 분기하고, 기다리고, 재시도하고, 멈출 수 있게 합니다.
시작하기 전에
- MAS가 설치되어 있고 체험 또는 요금제로 로그인한 상태. 체험은 무료 다운로드로 시작합니다. MAS 설치를 참고하세요.
- BlueStacks나 LDPlayer가 ADB가 켜진 채 실행 중이고 기기로 추가된 상태. BlueStacks 또는 LDPlayer 가이드를 참고하세요.
- 에뮬레이터가 계속 유지할 고정 해상도를 사용. 가이드는 세로 540x960, 240 DPI를 기준선으로 씁니다.
- Code Editor에 Code-Based 프로젝트가 열려 있는 상태. 시작하기를 참고하세요.
Asset Lab에서 템플릿 캡처
- 찾고 싶은 버튼이 있는 화면으로 앱을 가져옵니다.
- Code Editor에서 Assets 패널을 열고 Open Asset Helper를 클릭합니다. Asset Lab이 기기의 실제 화면과 함께 열립니다.
- 버튼 주위를 꼭 맞게 사각형으로 잘라 저장합니다. 잘라낸 조각이 Image Library로 가고 숫자 ID를 받습니다.
- 매크로가 인식해야 하는 모든 상태에 대해 반복합니다: 팝업 닫기 버튼, 확인 버튼, “done” 메시지.
- Assets 패널에서 각 이미지의 Copy ID를 클릭하고 스크립트 맨 위에 선언합니다.
import mas
images = mas.images({
"play_button": 201,
"close_popup": 202,
"out_of_energy": 203,
})mas.images는 각 ID에 읽기 쉬운 이름을 주고, 게시할 때 어떤 이미지를 묶을지 패커에 알려 줍니다. 템플릿은 jpg, png, gif, webp를 쓸 수 있고 각각 최대 10 MB입니다. Asset Lab을 참고하세요.
알맞은 호출 고르기
| 호출 | 쓰는 상황 | 반환 |
|---|---|---|
find_object(image) | 지금 화면을 한 번 보고 싶을 때 | ObjectMatch 또는 None |
find_object_retry(image, total_tries=3, time_sleep=2.0) | 대상이 잠시 뒤에 나타날 수 있을 때 | ObjectMatch 또는 마지막 시도 후 None |
find_any_object([a, b, c]) | 여러 템플릿이 모두 허용될 때: 팝업 변형, 두 가지 테마 | matched_template_id가 있는 첫 일치 |
find_objects(image, max_matches=10) | 같은 아이콘이 여러 번 나타나고 모두 원할 때 | 신뢰도순 목록 |
find_object_retry가 기본 대기 수단입니다. 실패한 시도 사이에 일정한 time_sleep 쉼을 두고 find_object를 최대 total_tries번 호출하며, 마지막 시도 후에는 쉬지 않습니다. 그 밖의 모든 키워드(threshold, search_region, screenshot)는 find_object로 전달됩니다. find_any_object_retry는 목록에 대해 같은 일을 합니다. 오래된 매크로를 위해 남아 있는 wait_for_object보다 이것들을 쓰세요.
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")ObjectMatch에는 x, y, center, matched_template_id가 있습니다. 점수는 담지 않으므로, 나중에 신뢰도를 읽는 대신 호출에서 임계값을 조정하세요.
search_region으로 검색 범위 좁히기
템플릿 매칭은 스크린샷 전체 위로 템플릿을 밀며 비교합니다. Region은 비교를 사각형 안으로 제한하므로 더 빠르고, 화면 다른 곳의 비슷한 것과 헷갈리지 않습니다. 좌표는 왼쪽 위 모서리 기준 픽셀입니다.
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)요소가 어디 있는지 알 때마다 영역을 쓰세요: 카운터는 상단 바, 동작 버튼은 하단, 대화 상자는 중앙. 영역은 Asset Lab에서 읽으세요. 좌표 선택기가 실제 화면의 픽셀 좌표를 보여 줍니다.
임계값 조정
threshold는 0.0부터 1.0까지이며 기본값은 0.8입니다. 일치로 인정되려면 이 값에 도달해야 합니다.
- 안티앨리어싱, 약간의 크기 변화, 버튼의 빛나는 효과 때문에 올바른 템플릿을 계속 놓치면 0.7로 낮추세요.
- 템플릿이 엉뚱한 곳에 일치하면, 예를 들어 비슷한 아이콘 두 개가 나란히 있거나 회색으로 비활성화된 모습으로도 나타나는 버튼이면 0.9로 올리세요.
- 0.7 아래로 내리기 전에 다시 자르세요. 그렇게 낮은 임계값은 같은 색이면 거의 무엇이든 받아들입니다.
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 glowfind_any_object로 팝업 처리
팝업은 녹화된 매크로가 깨지는 이유입니다. 모든 팝업을 아는 함수 하나를 매크로에 주고, 반복문의 각 회차 맨 위에서 호출하세요.
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는 목록을 받아 첫 일치를 반환합니다. search_strategy="best_match"는 대신 목록 전체에서 가장 높은 점수를 고르고, "priority_order"는 나열한 순서대로 템플릿을 시도합니다. True를 반환하면 반복문이 continue할 수 있으므로 다음 회차는 깨끗한 화면을 봅니다.
상태를 기다리는 LD플레이어 매크로 반복
기다림은 마감이 있는 반복문입니다. 짧은 대기는 find_object_retry가 다루고, 1분이 걸릴 수 있는 로딩 화면에는 진행 상황을 기록하고 깔끔하게 포기할 수 있도록 반복문을 직접 쓰세요.
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()은 초를 세고 시계가 바뀌어도 건너뛰지 않으므로 마감용 타이머로 알맞습니다. 모든 기다림은 끝나야 합니다. None을 반환하고 호출자가 실행을 멈출지 결정하게 하세요.
완전한 블루스택 이미지 인식 매크로
스크립트는 화면을 열고, 팝업을 정리하고, 버튼이 활성인 동안 탭하고, “out of energy” 템플릿이 나타나거나 시간 예산이 다하면 멈춥니다. 이미지 ID를 Image Library의 값으로 바꾸세요.
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()Code Editor에서 Run(F5)으로 실행하고 콘솔을 지켜보세요. 템플릿을 놓치면 잘라낸 조각을 먼저 고치고 임계값은 그다음입니다.
문제 해결
템플릿이 전혀 일치하지 않음
기기가 지금 실행 중인 것과 다른 해상도나 DPI에서 잘라냈거나, 잘라낸 조각에 바뀐 배경이 포함되어 있거나, 요소에 애니메이션이 있습니다. 에뮬레이터 디스플레이 설정을 캡처할 때의 설정과 비교하고, 더 조여서 다시 자르고, threshold=0.7을 시도하세요. 요소의 모습이 여러 가지면 각각 캡처하고 find_any_object를 쓰세요. mas.ImageNotFoundError는 ID가 Image Library에 아예 없다는 뜻입니다. Assets 패널에서 다시 복사하세요.
엉뚱한 것과 일치함
템플릿이 일반적입니다: 평범한 화살표, 단색 사각형, 두 번 나타나는 단어. 옆의 고유한 것을 자르거나, 임계값을 0.9로 올리거나, search_region을 넘겨 요소가 있는 곳에서만 찾게 하세요. find_objects는 템플릿이 임계값 이상으로 점수를 얻는 모든 위치를 보여 주므로 비슷한 것을 쉽게 찾아냅니다.
한 인스턴스에서는 되고 다른 인스턴스에서는 안 됨
두 번째 에뮬레이터 인스턴스가 다른 해상도나 DPI로 실행 중입니다. 템플릿 매칭은 픽셀 기반이라 540x960에서 캡처한 템플릿은 720x1280이나 다른 DPI에서 일치하지 않습니다. 모든 인스턴스를 같은 디스플레이 설정으로 맞추고 다시 시작하세요. 클라우드 기기에서는 캡처한 것과 같은 디스플레이 프리셋으로 기기를 만드세요. 인스턴스가 꼭 달라야 한다면 해상도별 템플릿 세트를 캡처하고 mas.get_screen_size()로 고르세요.
100% 안전한 자동화 도구는 없으므로, 책임감을 가지고 본인의 판단에 따라 자동화하세요.
다음 단계
관련 페이지
감사합니다. 잘못된 내용이 있으면 Discord에서 알려 주세요.
궁금한 점이 있으신가요? Discord에서 질문하기