게임 개발/Unreal Engine

[UE] Subsystem 활용한 Unreal 스타일 Singleton

지노윈 2022. 12. 19. 22:52
반응형

Subsystem 활용한 Unreal 스타일 Singleton

Singleton 패턴은 많은 짐이 있지만 무시할수 없는 기능성이 있습니다. 다행히도 Unreal Engine은 결점이 적은 방식으로 Singleton의 이점을 제공할 수 있는 방법이 있습니다.

나쁜 방식: C++ Static Singleton

class UMySingleton : public UObject
{
public:
	static UMySingleton* GetInstance() { return Instance; }

private:
	static UMySingleton* Instance;
};

C++ static class singleton의 장단점:

 

(장점) 프로그래머들이 즐겨사용하는 인터페이스

(단점) 잘못된 에디터와 상호작용
작업이 없다면, 에디터에서 게임이 여러번 실행되는 동안의 인스턴스들이 보존됩니다.

(단점) Class Default Object(CDO)와 잘못된 상호작용 

작업이 없다면, CDO가 생성될때 인스턴스가 생성됩니다.

(단점) 라이프타임이 불분명

주의 깊은 프로그래밍과 라이프타임 관리를 위해 분명한 의도가 필요합니다.

 

Unreal Subsystem

Unreal Engine은 Unreal Subsystem 이라 불리는 것이 있습니다. 이 서브시스템들은 글로벌하게 억세스가능한 모듈을 생성하는데 사용되며 명확한 라이프사이클을 갖습니다.

서브시스템의 라이프타임은 부모 클래스의 라이프타임을 따릅니다. 아래 표에서 보는 것과 같이 5가지의 부모가 있습니다.

Subsystem 부모 클래스 라이프타임
Engine UEngineSubsystem editor, in-game 모두, I think.
Editor UEditorSubsystem Editor 시작
GameInstance UGameInstanceSubsystem 게임이 시작되하자 마자, 게임이 종료될때까지 유지
LocalPlayer ULocalPlayerSubsystem ULocalPlayer의 라이프타임과 동일하며 레벨 이동에 따라 이동된다.
World UWorldSubsystem UWorld와 동일하며,  레벨별로 존재

Subsystem을 활용한 C++ singleton의 장단점:

 

(장점) 라이프타임이 자동으로 관리 됩니다.

올바른 Subsystem을 사용하는 것으로 인스턴스의 생성됨과 파괴됨이 보장됩니다.

(장점) 바라는 라이프타임을 명확히 할 수 있다.

UWordlSubsystem을 상속받은 Subsystem은 World가 존재하는 만큼 존재 할 수 있음이 명확합니다.

(장점) 더명확한 블루프린트 억세스.

(장점) Python 스크립트로 억세스 가능.

(단점) Unreal 크래스들의 라이프타임에 대한 이해가 필요하다.

(단점) MyClass::GetInstance()대신에 Unreal의 억세스 스타일을 학습해야 한다.

C++로 Subsystems 억세스

UGameInstance* GameInstance = ...;
UMyGameSubsystem* MySubsystem = GameInstance->GetSubsystem<UMyGameSubsystem>();

ULocalPlayer* LocalPlayer = ...;
UMyPlayerSubsystem* MySubsystem = LocalPlayer->GetSubsystem<UMyPlayerSubsystem>();

 

Subsystem Base Class

UCLASS(Abstract)
class ENGINE_API USubsystem : public UObject
{
	GENERATED_BODY()

public:
	USubsystem();

	/** Override to control if the Subsystem should be created at all.
	 * For example you could only have your system created on servers.
	 * It's important to note that if using this is becomes very important to null check whenever getting the Subsystem.
	 *
	 * Note: This function is called on the CDO prior to instances being created!
	 */
	virtual bool ShouldCreateSubsystem(UObject* Outer) const { return true; }

	/** Implement this for initialization of instances of the system */
	virtual void Initialize(FSubsystemCollectionBase& Collection) {}

	/** Implement this for deinitialization of instances of the system */
	virtual void Deinitialize() {}

private:
	friend class FSubsystemCollectionBase;
	FSubsystemCollectionBase* InternalOwningSubsystem;

};

 

https://benui.ca/unreal/subsystem-singleton/
 

Unreal-style Singletons with Subsystems

Subsystems are a simple way to make modular, globally-accessible logic.

benui.ca