개인프로젝트/IronBird

[IronBird #2] 배경 스크롤 + 총알 발사 구현

Client Side 2026. 5. 27. 21:46

IronBird 개발일지 #2

배경 스크롤 + 총알 발사 구현

Panner 머티리얼 · ABullet · SpawnActor · unreal-mcpython

🎯 목표

종스크롤 슈팅의 두 가지 핵심 요소를 구현한다. 배경이 위에서 아래로 흘러내려 비행감을 주고, 플레이어 기체에서 0.3초마다 총알이 자동 발사된다.

총알은 지금 SpawnActor/Destroy 방식으로 구현한다. 이 방식의 성능 문제를 측정하고, 다음 포스팅(#3)에서 Object Pool로 교체하는 Before/After 소재로 활용한다.

AI(unreal-mcpython MCP)로 머티리얼 자동 생성 → 내가 방향/연결 오류 발견 → 직접 수정 → Before 수치 기록

🔧 구현 내용

항목 내용
M_Background Panner 머티리얼, Unlit 셰이딩, unreal-mcpython으로 자동 생성
ABullet Tick 이동(+X), 거리 초과 시 Destroy(), 오버랩 바인딩
AIronBirdPawn 수정 SetTimer 0.3초 간격, SpawnActor<ABullet> 자동 발사

1. 배경 스크롤 - Panner 머티리얼

배경 스크롤은 C++ 코드 없이 머티리얼만으로 처리했다. Panner 노드가 UV 좌표를 시간에 따라 이동시켜 텍스처가 흘러가는 효과를 낸다. CPU 부하가 없고 GPU에서 처리되기 때문에 모바일에서 가장 효율적인 방법이다.

노드 구성: TexCoordinate → Panner(SpeedX=0.1, SpeedY=0) → TextureSample → 이미시브 컬러
셰이딩 모델: Unlit (라이팅 연산 없음 → 드로우콜 절약)

unreal-mcpython MCP 활용: 머티리얼 생성, Panner 노드 추가, Plane 배치, 머티리얼 적용까지 자동화. 수동 작업 예상 10분 → 약 1분으로 단축. 단, TextureSample → 이미시브 컬러 연결 오류와 UV 방향 문제는 직접 수정했다.

2. ABullet - 총알 클래스

지금은 동작 우선으로 Spawn/Destroy 방식을 사용한다. 다음 포스팅에서 Object Pool로 교체하면서 성능 차이를 측정할 예정이다.

// Tick에서 앞 방향으로 이동
AddActorLocalOffset(FVector(MoveSpeed * DeltaTime, 0.f, 0.f));

// 일정 거리 초과 시 제거 (Object Pool 도입 전 임시)
if (TravelDistance >= MaxDistance)
    Destroy();

// Pawn에서 0.3초마다 자동 발사
GetWorldTimerManager().SetTimer(FireTimerHandle, this,
    &AIronBirdPawn::Fire, FireInterval, true);

모바일 관점 메모: 매 프레임 Tick에서 이동 + 거리 체크를 하고, 0.3초마다 SpawnActor를 호출한다. 총알이 많아질수록 Tick 비용과 Spawn 비용이 선형으로 증가한다. #3에서 Object Pool로 교체 예정.

🔥 트러블슈팅

문제 1. 배경이 검은색으로 출력됨

원인: Unlit 셰이딩 모델에서는 베이스 컬러가 비활성화된다. TextureSample을 베이스 컬러에 연결해도 출력이 안 됨.

해결: TextureSample RGB → 이미시브 컬러에 연결. Unlit에서는 이미시브 컬러가 라이팅 없이 그대로 출력되는 올바른 핀이다.

문제 2. 배경이 좌우로 흘러감

원인: 탑뷰 카메라 기준에서 UV 방향이 예상과 달랐다. SpeedY=-0.05로 설정했지만 실제로는 좌우로 스크롤됨.

해결: SpeedX=0.1, SpeedY=0으로 변경. UV 방향은 카메라 시점 기준으로 직접 눈으로 확인하며 맞춰야 한다.

📊 Before 수치 기록 (Object Pool 도입 전)

#3 Object Pool 구현 후 동일 조건에서 비교할 기준 수치다.

항목 수치 비고
FPS 59.69 총알 51개 동시 존재
Frame 17.43ms  
Game 스레드 17.35ms Tick 과부하 예상
Draw 스레드 11.76ms  
Draws 212 모바일 목표 100 이하
Mesh draw calls 11.83 avg 최대 18.00

문제 인식: Game 스레드 17.35ms는 총알 51개 각각이 Tick을 실행하고 매 프레임 SpawnActor/Destroy를 반복하는 비용이다. 모바일 30fps 목표(33ms 예산) 기준으로는 여유가 있어 보이지만, 적과 이펙트가 추가되면 빠르게 한계에 달할 것이다.

💡 배운 것

• Panner 머티리얼은 CPU 부하 없이 GPU에서 처리. 모바일 배경 스크롤의 올바른 구현 방법이다.

• Unlit 셰이딩 모델에서는 이미시브 컬러를 사용해야 한다. 베이스 컬러는 비활성화된다.

• UV 방향은 카메라 시점 기준으로 달라진다. 탑뷰에서는 직접 눈으로 확인하며 맞춰야 한다.

• unreal-mcpython MCP로 에디터 작업을 자동화할 수 있다. 단, 노드 연결 오류는 직접 검증이 필요하다.

🟤 구현 영상

📌 다음 작업

[IronBird #3] Object Pool 구현

SpawnActor/Destroy → Object Pool 교체 후 동일 조건(총알 51개)에서 수치 재측정. Before/After 비교가 이 시리즈의 핵심 포스팅이다.