1. 개요
- 목표: 플레이어 처치 시 우측 상단에 킬 로그를 3초간 표시하고, 애니메이션 연출(슬라이드+페이드) 적용.
- 핵심 기술: C++ RPC (Client), WBP Animation, Widget Interaction, Vertical Box 최적화.
2. UI 구조 (Hierarchy)
- WBP_KillLogContainer: 화면에 고정된 바구니. Vertical Box를 사용하여 로그를 순차적으로 쌓음.
- WBP_KillLogEntry: 개별 로그 조각. 텍스트(Killer, Victim)와 아이콘으로 구성.
3. 주요 구현 내용
A. C++ 기반 UI 제어 (BindWidgetAnim)
- meta = (BindWidgetAnim)을 사용해 블루프린트에서 만든 애니메이션을 C++에서 직접 제어.
- NativeConstruct에서 애니메이션을 재생(PlayAnimation)하고, 타이머를 통해 자동 삭제 로직 구현.
- 학습 포인트: std::vector 대신 언리얼 전용 컨테이너인 TArray를 사용하고, TimerManager를 활용해 Tick 사용을 최소화함.
B. 멀티플레이어 동기화 (RPC)
- 흐름: GameMode(서버) -> 모든 PlayerController(클라이언트) -> KillLogContainer(로컬 UI).
- Client 매크로와 Reliable 옵션을 사용하여 네트워크 상에서 유실 없이 모든 클라이언트의 화면에 로그가 뜨도록 구현.
C. 렌더링 최적화
- 슬라이드 연출 시 Layout 수치 대신 Render Transform (Translation)을 수정하여 재계산(Re-layout) 비용을 절감.
4. 핵심 코드 요약 (Netmarble 실무 스타일)
// 1. 서버에서 모든 클라이언트에게 전파 (GameMode)
for (FConstPlayerControllerIterator It = GetWorld()->GetPlayerControllerIterator(); It; ++It)
{
if (AAFPlayerController* PC = Cast<AAFPlayerController>(It->Get()))
{
PC->Client_ShowKillLog(KillerName, KillerColor, VictimName, VictimColor);
}
}
// 2. 클라이언트 UI 추가 및 3초 뒤 자동 삭제 (Entry)
void UAFKillLogEntry::NativeConstruct()
{
Super::NativeConstruct();
PlayAnimation(AppearAnim); // "샥!" 하고 나타나는 연출
// 3초 후 삭제 예약 (효율적인 메모리 관리)
GetWorld()->GetTimerManager().SetTimer(DestroyTimerHandle, this, &UAFKillLogEntry::RemoveSelf, 3.0f, false);
}
5. QnA
- Q: 킬 로그를 GameState가 아닌 Controller에서 처리한 이유는?
- A: UI 생성 권한은 각 클라이언트의 로컬 컨트롤러에 있기 때문입니다. 서버 전용 클래스인 GameMode에서 발생한 이벤트를 각 클라이언트의 화면으로 전달하기 위해 PlayerController의 RPC를 활용했습니다.
- Q: 로그가 너무 많이 쌓이면 어떻게 처리하나?
- A: Vertical Box의 자식 개수를 체크하여 일정 수(예: 5개)가 넘어가면 가장 오래된 로그(RemoveChildAt(0))를 삭제하도록 최적화했습니다.
6. 회고
- 성과: 비전공자로서 어렵게 느껴졌던 C++와 블루프린트 애니메이션의 연동을 성공함.
- 성장: '네트워크 최적화'와 '가독성 좋은 UI 로직'에 대해 이해함.