일반적으로 많이 사용하는 Actor나 ActorComponent가 아니라, 간혹 Object를 바로 상속받거나 LocalPlayerSubsystem 같은 클래스를 상속받은 BP 클래스를 만들어서 사용해야 할 때가 있다. 그런데, 그렇게 상속받은 클래스에서 BlueprintFunctionLibrary에 정의된 함수를 호출하려고 하면 잘 안된다. 에디터에서 마우스 오른쪽을 눌러 다른 BP 함수 라이브러리의 함수를 찾아도 아예 보이지가 않는다.

 

정확한 원인은 잘 모르겠지만, BlueprintFunctionLibrary 함수를 호출할 때는 호출하려는 클래스의 GetWorld 함수 접근이 필요한데, Actor나 ActorComponent의 경우 해당 함수가 에디터에서도 접근할 수 있게 노출되어 있지만, UObject나 Subsystem 계통의 클래스들은 그게 안되어 있어서 생긴 문제로 보인다.

 

그래서, BP 클래스를 만들기 전에 부모 클래스를 c++로 만들고, Blueprintable 속성을 넣어주고, GetWorld 함수를 오버라이드하면 해결이 된다.

// MyGameSoundSubsystem.h
UCLASS(Blueprintable)
class MYGAME_API UMyGameSoundSubsystem : public ULocalPlayerSubsystem
{
    GENERATED_BODY()

public:
    virtual UWorld* GetWorld() const override;
//...
};
  
  
// MyGameSoundSubsystem.cpp
UWorld* UMyGameSoundSubsystem::GetWorld() const
{
#if WITH_EDITOR
    if (IsTemplate())
    {
        return nullptr;
    }
#endif

    return Super::GetWorld();
}

가장 간단한 방법은 위의 코드처럼 cpp 함수의 구현부에서 그냥 부모 함수만 호출해도 되긴 하는데, 에디터에서는 뭔가 또 다르게 작동하는 게 있어서 예외처리는 필요하다.

 

항상 위의 코드처럼 작성해야 하는 건 아니고 경우에 따라서는 부모 클래스나 Outer 클래스를 참조해야 할 필요도 있고, WorldContext를 명시적으로 노출해서 사용해야 하는 경우도 있다.

 

코드 출처: https://forums.unrealengine.com/t/can-you-use-a-blueprint-function-library-in-an-object-class/350918/31

 

ps. 일반적으로 Actor나 ActorComponent는 현재 맵(Level)의 월드에 귀속되지만, UObject를 상속받은 클래스 혹은 Subsystem 클래스들은 싱글턴처럼 쓰이는 경우가 많고, 현재 월드가 아닌 다른 월드(엔진 기본 월드?)에 귀속되어 있을 수 있다.

4.26 기준.

 

1.Diff 후 BP 컴파일 에러

소스 컨트롤과 Diff를 하고 난 이후 게임을 컴파일하면 느닷없이 컴파일 에러가 뜰 때가 있음.

자세히 보면 에러나 블루프린트(BP) 파일에 temp 어쩌고 하는 이름이 들어 있음.

Diff를 할 때 임시로 생성한 예전 BP파일을 컴파일하려다가 오류가 발생하는 걸로 보임.

 

대처법: 에디터를 껐다가 다시 켠다.

 

2.BP 컴파일 도중 검색하면 에디터 먹통

Find in blutprints에서 뭘 찾고 있는 동안 BP를 컴파일하면 에디터가 간혹 먹통이 된다.

 

대처법: 작업 관리자에서 에디터를 강제로 종료하고 다시 켠다.

 

3.PIE 도중 검색하면 에디터 먹통

에디터에서 게임을 플레이(PIE)하는 도중에 Find in blutprints에서 뭘 찾으면 간혹 에디터가 먹통이 된다.

 

대처법: 작업 관리자에서 에디터를 강제로 종료하고 다시 켠다.

블루프린터의 "인터페이스"라는 클래스는 함수 정의만 할 수 있고 구현은 할 수 없는 껍데기 클래스이다. 이를 처음 접하면, c++의 pure virtual function만 모아 둔 클래스와 비슷하다고 생각할 수 있다. 즉, c++에서 다중 상속을 이용한 인터페이스 구현처럼 보이기는 하지만, 성격이 좀 다르다.

 

일단, 언리얼 엔진에서 인터페이스용 클래스는 c++과 달리 부모로서 추가되는 게 아니다. 블루 프린트 클래스에서 부모 클래스는 단 하나만 존재할 수 있다. 인터페이스를 추가하고자 할 때는, 클래스 속성에서 Interfaces 카테고리에서 Add를 해서 추가해야 한다.

 

인터페이스 함수를 호출하기 위해서는 캐스팅이 필요없다. 예를 들어, BP_Parent라는 부모 클래스가 있고, 이를 상속 받은 BP_Child 클래스가 있다. BP_Child 클래스는 BP_Interface라는 인터페이스를 추가했고, 함수부분을 구현했다.

 

인터페이스에서 정의된 함수를 호출하려고 보면, BP_Child 클래스 뿐 아니라 BP_Parent 클래스에 대해서도 함수 호출이 가능하다. 인터페이스 함수의 인자를 자세히 보면, 특정 클래스가 아니라 Object Refernece를 받는다. 즉, 아무 클래스에 대해서 호출이 가능하다. 그런데, 해당 인터페이스를 상속 받지 않은 클래스에서 어떻게 함수 호출이 가능할까? c++에서는 컴파일 에러가 날 상황인데, 언리얼에서는 어떻게 가능한가?

 

알고 보니, 인터페이스 함수 내부에서의 처리는 c++의 상속 개념이라기 보다는 메시지 함수와 비슷하다고 한다. 그래서, 어떤 클래스에 대해서도 호출이 가능하다. 해당 클래스에 인터페이스 함수가 구현되어 있으면 처리를 하지만, 구현되어 있지 않으면 조용히 실패를 한다고 한다. 즉, c++ 처럼 컴파일 에러가 발생하지 않기 때문에 주의가 필요하다.

 

+ Recent posts