UE Subsystems
前言
文章内容取自Subsystems,本篇文章只是云笔记,请看原文章进行学习
定义:
Subsystems是一套可以定义自动实例化和释放的类的框架。这个框架允许你从5类里选择一个来定义子类(只能在C++定义):
- UEngineSubsystem
- UEngine* GEngine
- UEditorSubsystem
- UEditorEngine* GEditor
- UGameInstanceSubsystem
- UGameInstance* GameInstance
- UWorldSubsystem
- UWorld* World
- ULocalPlayerSubsystem
- ULocalPlayer* LocalPlayer
优点
- 自动实例化
- 这些的UMyXXXSubsystem类,会在合适的时机被创建出对象,然后在合适的时机释放,这个过程是自动化的。不需要自己手写创建代码。也不需要自己显式的定义变量,Subsystems已经定义好方便友好的访问接口了。
- 托管生命周期
- 根据你选择的父类不同,引擎会为创建出来的Subsystem实现出不同的生命周期。因此官方文档里会称这5个父类为5个不同的生命周期。根据你选择的生命周期不同,
Initialize()
和Deinitialize()
会自动的在合适的时机被调用。一个Subystem类型也有可能根据需要被自动的被创建出多个实例。这些里面的繁琐逻辑自己都不用操心。
- 根据你选择的父类不同,引擎会为创建出来的Subsystem实现出不同的生命周期。因此官方文档里会称这5个父类为5个不同的生命周期。根据你选择的生命周期不同,
使用:
重载函数
virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
virtual void Initialize(FSubsystemCollectionBase& Collection)override;
virtual void Deinitialize()override;
C++访问
//UMyEngineSubsystem获取
UMyEngineSubsystem* MySubsystem = GEngine->GetEngineSubsystem<UMyEngineSubsystem>();
//UMyEditorSubsystem的获取
UMyEditorSubsystem* MySubsystem = GEditor->GetEditorSubsystem<UMyEditorSubsystem>();
//UMyGameInstanceSubsystem的获取
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance(...);
UMyGameInstanceSubsystem* MySubsystem = GameInstance->GetSubsystem<UMyGameInstanceSubsystem>();
//UMyWorldSubsystem的获取
UWorld* World=MyActor->GetWorld(); //world用各种方式也都可以
UMyWorldSubsystem* MySubsystem=World->GetSubsystem<UMyWorldSubsystem>();
//UMyLocalPlayerSubsystem的获取
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(PlayerController->Player)
UMyLocalPlayerSubsystem * MySubsystem = LocalPlayer->GetSubsystem<UMyLocalPlayerSubsystem>();
//我省略了一些宏标记和注释,因为函数名字是不言自明的。
UCLASS()
class ENGINE_API USubsystemBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
static UEngineSubsystem* GetEngineSubsystem(TSubclassOf<UEngineSubsystem> Class);
static UGameInstanceSubsystem* GetGameInstanceSubsystem(UObject* ContextObject, TSubclassOf<UGameInstanceSubsystem> Class);
static ULocalPlayerSubsystem* GetLocalPlayerSubsystem(UObject* ContextObject, TSubclassOf<ULocalPlayerSubsystem> Class);
static UWorldSubsystem* GetWorldSubsystem(UObject* ContextObject, TSubclassOf<UWorldSubsystem> Class);
static ULocalPlayerSubsystem* GetLocalPlayerSubSystemFromPlayerController(APlayerController* PlayerController, TSubclassOf<ULocalPlayerSubsystem> Class);
};
生命周期:
- UGameInstanceSubsystem: 数量1。依赖于GameInstance的生命周期,从游戏的启动开始创建,游戏退出时销毁。这里的一场游戏指的是Runtime或PIE模式的运行的都算,一场游戏里可能会创建多个World切换。
- UWorldSubsystem: 数量可能>1。依赖于UWorld,一般情况下生命周期与GameMode一样, 切换关卡会销毁和创建。但编辑器模式下视口里的场景其实也是个World,其生命周期与Editor一样。
- UEditorSubsystem: 只在编辑器模式下存在, 数量1。依赖于GEditor, 从编辑器启动开始创建,到编辑器退出时销毁。
- UEngineSubsystem: 依赖于GEngine, Editor或Runtime模式都是全局唯一。从进程启动开始创建,进程退出时销毁。
- ULocalPlayerSubsystem: 数量取决于LocalPlayer数量。依赖于ULocalPlayer,一般情况下生命周期与GameInstance一致。
UEngineSubsystem和UEditorSubsystem属于UDynamicSubsystem,可以根据Module的加载释放来创建销毁
用法:
1.遍历
const TArray<USourceControlSubsystem*>& systems= GEngine->GetEngineSubsystemArray<USourceControlSubsystem>();
2.蓝图继承
C++创建抽象基类–>蓝图继承抽象基类–>显式加载蓝图基类
UCLASS(abstract, Blueprintable, BlueprintType)
class HELLO_API UMyGameInstanceSubsystemBase : public UGameInstanceSubsystem
{
}
UObject* bpAsset = LoadObject<UObject>(NULL, TEXT("/Game/BP_MyGameInstanceSubsystem.BP_MyGameInstanceSubsystem_C"));
3.同一个BaseType下的多个Subsystem可以定义依赖顺序
任务系统依赖于计分系统
void UMyTaskSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
//初始化依赖项
Collection.InitializeDependency(UMyScoreSubsystem::StaticClass());
//获取
UMyScoreSubsystem* ss=((FSubsystemCollection<UGameInstanceSubsystem>&)Collection).GetSubsystem<UMyScoreSubsystem>(UMyScoreSubsystem::StaticClass());
}
4.Tick
UCLASS()
class HELLO_API UMyTickSubsystem : public UGameInstanceSubsystem,public FTickableGameObject
{
GENERATED_BODY()
public:
virtual void Tick(float DeltaTime) override;
virtual bool IsTickable() const override { return !IsTemplate(); }//不是CDO才Tick
virtual TStatId GetStatId() const override{RETURN_QUICK_DECLARE_CYCLE_STAT(UMyScoreSubsystem, STATGROUP_Tickables);}
};