나만의 작은 도서관

[TIL][C++] 250919 MMO 서버 개발 105일차: [언리얼] 게임인스턴스를 가져오는 2가지 방법, 블루프린트 Sequence 노드 본문

Today I Learn

[TIL][C++] 250919 MMO 서버 개발 105일차: [언리얼] 게임인스턴스를 가져오는 2가지 방법, 블루프린트 Sequence 노드

pledge24 2025. 9. 19. 04:29
주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다. 

[언리얼] 게임인스턴스를 가져오는 2가지 방법

 

첫 번째) UWorld::GetGameInstance

// 정의
UGameInstance* UWorld::GetGameInstance() const
{
    return OwningGameInstance;
}

// 사용
void AMyActor::BeginPlay()
{
    Super::BeginPlay();

    // 액터는 이미 World에 소속되어 있으므로 GetWorld 사용 가능
    if (auto* GI = Cast<UMyGameInstance>(GetWorld()->GetGameInstance()))
    {
        GI->HandleSomething();
    }
}
  • World.h 헤더로부터 게임인스턴스를 얻는 방식. Actor의 경우 World가 생성된 다음 시점인 BeginPlay이후 호출하면 반드시 게임인스턴스를 얻을 수 있다.
  • 반면, 생성자에서 사용할 경우 GetWorld 자체가 nullptr을 반환할 수 있어 GetWorld()→GetGameInstance()와 같이 사용하면 크래시가 발생할 수 있다.

 

추가 팁) GetWorld는 UObject 소속의 함수이다.

// UObject 클래스에서
virtual UWorld* GetWorld() const override;
  • 이것 때문에 GetWorld는 UObject 계열의 클래스에서만 호출 가능하며, 네이티브 라이브러리에서는 호출이 불가능하다.

 

두 번째) UGameplayStatics::GetGameInstance();

// 정의
UGameInstance* UGameplayStatics::GetGameInstance(const UObject* WorldContextObject)
{
    if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::ReturnNull))
    {
        return World->GetGameInstance();
    }
    return nullptr;
}

// 사용
UGameplayStatics::GetGameInstance(GetWorld());
  • WorldContextObject로부터 안전하게 UWorld를 얻을 수 있는 방식이며, 정적 함수이다.
  • WorldContextObject는 현재 월드에 존재하는 UObject*를 넘겨주면 되며, 보통 AActor*, UWorld*, UWidget* 등을 넘겨준다.
  • 네이티브 라이브러리와 같이 UObject 기반 클래스가 아닌 곳에서는 GetWorld를 사용할 수 없는 상황에선 요긴하게 사용할 수 있다.

 

GWorld를 사용해 보는 것도 고려하자

  • UGameplayStatics::GetGameInstance()의 단점은 현재 활성화된 월드에 소속된 객체를 넘겨줘야 한다는 것이다. 월드와 독립적으로 운영되는 네이티브 라이브러리 같은 경우 활성화된 월드 소속 객체를 얻어내는 것이 영 찝찝하다.
  • 왜냐하면 라이브러리가 UObject 기반 객체로부터 호출되는 구조라면 그나마 객체를 넘겨줄 여건이 되지만, 그렇지 않은 경우에는 미리 객체를 들고 있어야 할 수밖에 없기 때문.
  • 이런 경우에는 그냥 전역 포인터로 관리되는 GWorld를 사용하는 것도 나쁘진 않다.

 

GWorld?

// 어디서든 접근 가능
UWorld* CurrentWorld = GWorld;
  • GWorld는 언리얼 엔진의 전역 변수로, 현재 활성화된 월드의 참조를 가지고 있는 포인터이다.
  • Engine.h 또는 관련 헤더 파일에서 얻을 수 있기 때문에 네이티브 라이브러리에서도 쉽게 접근할 수 있다.
  • 다만 조심해야 할 점은 일반적이지는 않지만(?) 월드를 동시에 여러 개가 존재하는 멀티 월드 환경을 구축했다면 GWorld 사용은 위험하다.
  • 그래서 현대적인 언리얼 문법에선 GWorld 사용을 자제하라고 하는데, 이게 NetMode의 StandAlone 개수와는 또 무관하여(StandAlone의 Number Of Players의 크기를 3으로 하면 GWorld가 각 StandAlone에 하나씩 총 3개 존재하기 때문에) 의도적으로 멀티 월드 콘셉트를 잡지 않는 이상 문제될 건 없다.

결론)

  • World에 소속된 UObject 기반 클래스(ex. AActor)에서 게임인스턴스를 얻고 싶다면 GetWorld() 함수를 쓰면 된다.
  • UObject 기반 클래스가 아니지만 월드에 소속된 UObject가 호출하는 구조라면UGameplayStatics::GetGameInstance()함수를 사용하면 된다.
  • UObject 기반 클래스가 아니고, 월드에 소속된 UObject가 호출하는 구조도 아니라면 그냥 GWorld를 써라.
    • (사실 다 필요없고 GWorld만 써도 된다.)

[언리얼] 블루프린트 Sequence 노드

https://velog.io/@enamu/UE4-%EC%96%B8%EB%A6%AC%EC%96%BC%EC%97%94%EC%A7%84-%EB%B8%94%EB%A3%A8%ED%94%84%EB%A6%B0%ED%8A%B8-Sequence

  • 블로그 글을 보던 도중 branch 노드랑 비슷하게 생긴 Sequence 노드를 보고 “비슷한 거겠지”하고 알아둘 겸 가벼운 마음으로 서칭 했는데, 굉장히 노드를 깔끔하게 정리할 수 있는 좋은 노드라는 것을 깨닫고 정리한다.
  • Sequence노드는 순차적으로 로직을 처리하는 노드로, 위에서부터 차례대로 연결된 핀을 실행한다.

 

약간의 아쉬움

  • 중간에 break를 하는 기능은 없는 듯 하다. 비슷하게끔 만드는 방법으로 모든 실행핀 앞에 branch 노드를 넣는 패턴이 있다.
  • 아니면 그냥 아싸리 함수로 묶어서 return 하는 방법을 사용해야 한다.