카테고리 보관물: 개발

Unreal 동적으로 생성된 액터의 스프라이트 overlap 이벤트가 발생하지 않는 문제 해결

개요

타일맵과 마찬가지로 각종 액터를 코드를 통해 동적으로 생성했습니다. 정상적으로 나타나는데 의도한 동작을 하지 않았습니다. 수동으로 추가한 같은 종류의 액터는 정상적으로 동작했습니다. 이전과 같이 뭔가 생성 타이밍의 문제가 아닐까 생각되었습니다.

문제 확인

해당 액터는 하나의 스프라이트가 추가 되어 있었습니다. 플레이어가 스프라이트와 겹치면 의도한 동작을 하도록 작업되어 있습니다. 동적으로 생성된 액터는 overlap 이벤트가 전혀 발생하지 않았습니다. 수동으로 배치한 액터에서는 로그가 정상적으로 출력되어 문제가 없었습니다.

액터에 추가된 스프라이트
액터에 추가된 스프라이트

해결

타일맵에서 Navigation Paths 가 동작하지 않는 문제와 비슷했습니다. 해당 액터의 BeginPlay 메소드에서 다음과 같이 시간 지연 후 등록해 주면 정상적으로 동작합니다.

FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda([&]() {
    GetWorld()->GetTimerManager().ClearTimer(TimerHandle);

    YourSpriteComponent = GetComponentByClass<UPaperSpriteComponent>();

    if (YourSpriteComponent != nullptr) {
        YourSpriteComponent->OnComponentBeginOverlap.AddDynamic(this, &AYourClass::OnBeginOverlap);
    }
}), 0.2f, false);

이 액터와 같은 형식의 다른 액터들도 동적으로 생성했을 경우 같은 문제가 있었습니다. 다른 액터들도 위의 코드를 추가해서 정상적으로 동작하도록 했습니다.

이 문제도 결과적으로 보면 간단한데 정확하게 문제를 식별하고 적절한 처리를 추가하는데 생각보다 시간이 많이 소요되었습니다. 필자와 같은 문제를 겪으신 분들께 도움이 되었으면 합니다.

Unreal 동적으로 생성된 타일맵의 Navigation Paths 가 제대로 적용되지 않는 문제 해결

개요

개발 중인 게임에서 외부 자료로 타일맵을 생성하도록 작업했습니다. 모든 것이 정상이라고 생각되었는데 그 위에 StateTree 를 이용한 액터를 배치하니 이상한 현상이 있었습니다. 원래 Navigation Paths 가 생성된 곳에서만 동작을 하는 것이 원칙인데 그곳을 벗어나는 문제가 있었습니다.

문제 확인 및 범위 한정

에디터에서 게임을 실행하고 P(Navigation) 키를 눌러보면 검은색의 Paths 를 볼 수 있는데 이것이 전혀 나타나지 않았습니다.

Navigation Paths 가 제대로 나타나는 경우. 아래쪽 타일에 Collision이 적용되어 있다
Navigation Paths 가 제대로 나타나는 경우. 아래쪽 타일에 Collision이 적용되어 있다

C++ 코드를 이용해서 타일맵을 생성했습니다. 수동으로 생성한 타일맵에서는 정상적으로 나타났습니다. 동적으로 타일맵이 생성될 때 타이밍이나 등록 문제 때문에 정상적으로 동작하지 않는 것으로 판단되었습니다. 그래서 이 부분을 중심으로 이리저리 코드를 변경해 보았습니다. 그리고 이상한 점이 Outliner 에서 동적으로 생성된 타일맵을 한번 선택해 주면 정상적으로 동작했습니다. 아예 안되는 것은 아니라는 것을 확인했습니다.

해결

결국 등록과 관련한 문제였습니다. 다음과 같이 타이머를 이용해서 약간의 시간 지연 후 등록과정을 거치면 정상적으로 Navigation Paths 가 나타납니다.

FTimerHandle TimerHandle;
GetWorld()->GetTimerManager().SetTimer(TimerHandle, FTimerDelegate::CreateLambda([&amp;]() {
    GetWorld()->GetTimerManager().ClearTimer(TimerHandle);

    UNavigationSystemV1* NavSystem = UNavigationSystemV1::GetCurrent(GetWorld());
    if (NavSystem) { 
        NavSystem->OnActorRegistered(this);
        NavSystem->Build();
    }
}), 0.2f, false);

핵심은 7번째 행인데 OnActorRegistered 메소드 수행 후 빌드해 주면 정상적으로 StateTree 를 사용한 액터가 정상적으로 동작하게 됩니다.

결과만 보았을 때는 간단한 것 같지만 이것을 알아내는데 상당한 시간이 소요되었습니다. 필자와 같은 문제를 겪은 분들께 도움이 되었으면 좋겠습니다.