UEngineSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)
UEngine* GEngine
代表引擎,数量1。 Editor或Runtime模式都是全局唯一,从进程启动开始创建,进程退出时销毁。
UEngine::Init()
UEditorSubsystem(继承自 UDynamicSubsystem,UDynamicSubsystem继承自 USubsystem)
UEditorEngine* GEditor
代表编辑器,数量1。 顾名思义,只在编辑器下存在且全局唯一,从编辑器启动开始创建,到编辑器退出时销毁。
UGameInstanceSubsystem (继承自 USubsystem)
UGameInstance* GameInstance
代表一场游戏,数量1。 从游戏的启动开始创建,游戏退出时销毁。这里的一场游戏指的是Runtime或PIE模式的运行的都算,一场游戏里可能会创建多个World切换。
UWorldSubsystem (继承自 USubsystem)
UWorld* World
代表一个世界,数量可能>1。其生命周期,跟GameMode是一起的。(EWorldType:Game,Editor,PIE,EditorPreview,GamePreview等 )
ULocalPlayerSubsystem (继承自 USubsystem)
ULocalPlayer* LocalPlayer:代表本地玩家,数量可能>1。
UE支持本地分屏多玩家类型的游戏,但往往最常见的是就只有一个。LocalPlayer虽然往往跟PlayerController一起访问,但是其生命周期其实是跟UGameInstance一起的(默认一开始的时候就创建好一定数量的本地玩家),或者更准确的说是跟LocalPlayer的具体数量挂钩(当然你也可以运行时动态调用AddLocalPlayer)。
更适用的生命周期
更简
更模块化、更优雅、更封装、更易于维护、移植复用
GameInstance 中将任务系统,计分系统,经济系统、对话系统等多个Manager 写在一起,会变得臃肿
Subsystems 可以为不同的 Manager 创建对应的Subsystems
如 Manager 划分,
更模块化,代码显得优雅
解耦性高,易于维护、分工协作;易于移植复用
模块间的数据访问具有更好的封装性
更友好的访问接口
Subsystem 无需覆盖引擎类。
创建过程,涉及 FSubsystemCollectionBase
FSubsystemCollectionBase::Initialize()
FSubsystemCollectionBase::AddAndInitializeSubsystem()
FSubsystemCollectionBase::Deinitialize()
参考附录源码 或者 EngineDir\Engine\Source\Runtime\Engine\Private\Subsystems\SubsystemCollection.cpp
默认重载函数
C++ 访问
// UMyEngineSubsystem 获取
UMyEngineSubsystem* MyEngineSubsystem = GEngine->GetEngineSubsystem<UMyEngineSubsystem>();
// UMyEditorSubsystem 获取
UMyEditorSubsystem* MyEditorSubsystem = GEditor->GetEditorSubsystem<UMyEditorSubsystem>();
// UMyGameInstanceSubsystem 获取
//UGameInstance* GameInstance = GetWorld()->GetGameInstance();
UGameInstance* GameInstance = UGameplayStatics::GetGameInstance();
UMyGameInstanceSubsystem* MyGameInstanceSubsystem = GameInstance->GetSubsystem<UMyGameInstanceSubsystem>();
// UMyWorldSubsystem 获取
UMyWorldSubsystem* MyWorldSubsystem = GetWorld()->GetSubsystem<UMyWorldSubsystem>();
// UMyLocalPlayerSubsystem 获取
ULocalPlayer* LocalPlayer = UGameplayStatics::GetPlayerController()->GetLocalPlayer();
UMyLocalPlayerSubsystem* MyLocalPlayerSubsystem = LocalPlayer->GetSubsystem<UMyLocalPlayerSubsystem>();
引擎自带 USubsystemBlueprintLibrary 访问方法
UCLASS()
class ENGINE_API USubsystemBlueprintLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
/** Get a Game Instance Subsystem from the Game Instance associated with the provided context */
UFUNCTION(BlueprintPure, Category = "Engine Subsystems", meta = (BlueprintInternalUseOnly = "true"))
static UEngineSubsystem* GetEngineSubsystem(TSubclassOf<UEngineSubsystem> Class);
/** Get a Game Instance Subsystem from the Game Instance associated with the provided context */
UFUNCTION(BlueprintPure, Category = "GameInstance Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
static UGameInstanceSubsystem* GetGameInstanceSubsystem(UObject* ContextObject, TSubclassOf<UGameInstanceSubsystem> Class);
/** Get a Local Player Subsystem from the Local Player associated with the provided context */
UFUNCTION(BlueprintPure, Category = "LocalPlayer Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
static ULocalPlayerSubsystem* GetLocalPlayerSubsystem(UObject* ContextObject, TSubclassOf<ULocalPlayerSubsystem> Class);
/** Get a World Subsystem from the World associated with the provided context */
UFUNCTION(BlueprintPure, Category = "GameInstance Subsystems", meta = (WorldContext = "ContextObject", BlueprintInternalUseOnly = "true"))
static UWorldSubsystem* GetWorldSubsystem(UObject* ContextObject, TSubclassOf<UWorldSubsystem> Class);
/**
* Get a Local Player Subsystem from the LocalPlayer associated with the provided context
* If the player controller isn't associated to a LocalPlayer nullptr is returned
*/
UFUNCTION(BlueprintPure, Category = "LocalPlayer Subsystems", meta = (BlueprintInternalUseOnly = "true"))
static ULocalPlayerSubsystem* GetLocalPlayerSubSystemFromPlayerController(APlayerController* PlayerController, TSubclassOf<ULocalPlayerSubsystem> Class);
private:
static UWorld* GetWorldFrom(UObject* ContextObject);
};
支持委托
支持普通变量和函数
支持蓝图调用
UCLASS()
class DESIGNPATTERNS_API UScoreGameInsSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
// 是否允许被创建
virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
// 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
// 释放
virtual void Deinitialize() override;// 声明委托
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FScoreChanged, int32, CurrentScore);
UPROPERTY(BlueprintAssignable)
FScoreChanged ScoreChange;
UFUNCTION(BlueprintCallable, Category = "MySubsystem | ScoreGameInsSubsystem")
int32 AddScore(int32 BaseScore);
private:
int32 Score;
};
void UScoreGameInsSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
Super::Initialize(Collection);
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__""));
}
void UScoreGameInsSubsystem::Deinitialize()
{
Super::Deinitialize();
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__""));
}
int32 UScoreGameInsSubsystem::AddScore(int32 BaseScore)
{
Score = UKismetMathLibrary::Max(0, Score + BaseScore);
// 调用委托
ScoreChange.Broadcast(Score);
return Score;
}
支持创建抽象类,多个派生类,支持蓝图继承,支持遍历访问
注意UCLASS(Type)
注意每种类型的 Subsystem 只能创建一个实例
C++访问
GetWorld()->GetGameInstance()->GetSubsystem<T>()
GetWorld()->GetGameInstance()->GetSubsystemArray<T>()
使用示例
/**
* 抽象类 USourceControlSubsystem
*/
UCLASS(Abstract, Blueprintable, BlueprintType)
class DESIGNPATTERNS_API USourceControlSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
// ShouldCreateSubsystem 默认返回 True// 可重载
UFUNCTION(BlueprintCallable, BlueprintNativeEvent, Category = "MySubsystem | SourceControl")
FString GetPlatformName();
};
/**
* 派生类 UGitSubsystem
*/
UCLASS()
class DESIGNPATTERNS_API UGitSubsystem : public USourceControlSubsystem
{
GENERATED_BODY()
public: // 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override {
Super::Initialize(Collection);
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"),*GetName());
}
// 释放
virtual void Deinitialize() override {
Super::Deinitialize();
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"),*GetName());
}
virtual FString GetPlatformName_Implementation()override {
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【Git】"));
return TEXT("Git");
}
void Help() {
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" Help Command"));
}
};
/**
* 派生类 USVNSubsystem
*/
UCLASS()
class DESIGNPATTERNS_API USVNSubsystem : public USourceControlSubsystem
{
GENERATED_BODY()
public: // 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override {
Super::Initialize(Collection);
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"), *GetName());
}
// 释放
virtual void Deinitialize() override {
Super::Deinitialize();
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【%s】"), *GetName());
}
virtual FString GetPlatformName_Implementation()override {
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"【SVN】"));
return TEXT("SVN");
}
};
/**
* 用于测试 ASourceControlActor
*/
UCLASS(Blueprintable, BlueprintType)
class DESIGNPATTERNS_API ASourceControlActor : public AActor
{
GENERATED_BODY()
public:
ASourceControlActor(){}virtual void BeginPlay()override {
Super::BeginPlay();
// 获取单个 Subsystem
UGitSubsystem* GitSubsystem = GetWorld()->GetGameInstance()->GetSubsystem<UGitSubsystem>();
GitSubsystem->Help();
// 获取多个 Subsystem,继承自同个抽象类
const TArray<USourceControlSubsystem*> SourceControlSubsystems = GetWorld()->GetGameInstance()->GetSubsystemArray<USourceControlSubsystem>();
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"********************* 遍历USourceControlSubsystem ********************"));
for (USourceControlSubsystem* ItemSubSystem : SourceControlSubsystems)
{
ItemSubSystem->GetPlatformName();
}
}
};
蓝图调用
支持Tick, 需继承 FTickableGameObject,参考 UAutoDestroySubsystem 写法
UCLASS()
class DESIGNPATTERNS_API UScoreGameInsSubsystem : public UGameInstanceSubsystem, public FTickableGameObject
{
GENERATED_BODY()
public:virtual void Tick(float DeltaTime)override{ UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__"Ping Pong"));}
virtual bool IsTickable()const override { return !IsTemplate(); } //判断是否是 CDO,避免执行两次 Tick
virtual TStatId GetStatId() const override { RETURN_QUICK_DECLARE_CYCLE_STAT(UMyScoreSubsystem, STATGROUP_Tickables); }
};
支持 Subsystem 之间的访问
支持多个Subsystem定义依赖顺序,再初始化时调用 Collection.InitializeDependency(UScoreGameInsSubsystem::StaticClass());
可以再编辑器 和 运行时 使用
UCLASS()
class DESIGNPATTERNS_API UMyWorldSubsystem : public UWorldSubsystem
{
GENERATED_BODY()
public:
// 是否允许被创建
virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
// 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
// 释放
virtual void Deinitialize() override;FString GetWorldType();
};
void UMyWorldSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" [World] %-20s\t[Type] %s\t"), *GetWorld()->GetName(), *GetWorldType());
}
void UMyWorldSubsystem::Deinitialize()
{
UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__" [World] %-20s\t[Type] %s\t"), *GetWorld()->GetName(), *GetWorldType());
}
FString UMyWorldSubsystem::GetWorldType()
{
FString WorldTypeName;
switch (GetWorld()->WorldType) {
case EWorldType::None: {WorldTypeName = TEXT("None"); }break;
case EWorldType::Game: {WorldTypeName = TEXT("Game"); }break;
case EWorldType::Editor: {WorldTypeName = TEXT("Editor"); }break;
case EWorldType::PIE: {WorldTypeName = TEXT("PIE"); }break;
case EWorldType::EditorPreview: {WorldTypeName = TEXT("EditorPreview"); }break;
case EWorldType::GamePreview: {WorldTypeName = TEXT("GamePreview"); }break;
case EWorldType::GameRPC: {WorldTypeName = TEXT("GameRPC"); }break;
case EWorldType::Inactive: {WorldTypeName = TEXT("Inactive"); }break;
default: WorldTypeName = TEXT("default");
};
return WorldTypeName;
}
需要再 .build.cs 添加 EditorSubsystem 模块
if (Target.bBuildEditor)
{
PublicDependencyModuleNames.AddRange(new string[] { "EditorSubsystem" });
}
需要添加头文件
编译模式记得选Editor 模式
#include "EditorSubsystem.h"
UCLASS()
class DESIGNPATTERNS_API UMyEditorSubsystem : public UEditorSubsystem
{
GENERATED_BODY()
public:// 是否允许被创建
virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
// 初始化
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
// 释放
virtual void Deinitialize() override;
};
检查、验证资产
从 EditorUtilityBlueprint 中选择父类 EditorValidatorBase
SubsystemCollection.cpp
FSubsystemCollectionBase::Initialize()
FSubsystemCollectionBase::AddAndInitializeSubsystem()
FSubsystemCollectionBase::Deinitialize()
void FSubsystemCollectionBase::Initialize(UObject* NewOuter)
{
if (Outer != nullptr)
{
// already initialized
return;
}
Outer = NewOuter;
check(Outer);
if (ensure(BaseType) && ensureMsgf(SubsystemMap.Num() == 0, TEXT("Currently don't support repopulation of Subsystem Collections.")))
{
check(!bPopulating); //Populating collections on multiple threads?if (SubsystemCollections.Num() == 0)
{
FSubsystemModuleWatcher::InitializeModuleWatcher();
}
TGuardValue<bool> PopulatingGuard(bPopulating, true);
if (BaseType->IsChildOf(UDynamicSubsystem::StaticClass())) // 判断是否是 UDynamicSubsystem 的子类
{
for (const TPair<FName, TArray<TSubclassOf<UDynamicSubsystem>>>& SubsystemClasses : DynamicSystemModuleMap)
{
for (const TSubclassOf<UDynamicSubsystem>& SubsystemClass : SubsystemClasses.Value)
{
if (SubsystemClass->IsChildOf(BaseType))
{
AddAndInitializeSubsystem(SubsystemClass);
}
}
}
}
else // 不是 UDynamicSubsystem 的子类
{
TArray<UClass*> SubsystemClasses;
GetDerivedClasses(BaseType, SubsystemClasses, true);for (UClass* SubsystemClass : SubsystemClasses)
{
AddAndInitializeSubsystem(SubsystemClass);
}
}
// Statically track collections
SubsystemCollections.Add(this);
}
}
void FSubsystemCollectionBase::Deinitialize()
{
// Remove static tracking
SubsystemCollections.Remove(this);
if (SubsystemCollections.Num() == 0)
{
FSubsystemModuleWatcher::DeinitializeModuleWatcher();
}
// Deinit and clean up existing systems
SubsystemArrayMap.Empty();
for (auto Iter = SubsystemMap.CreateIterator(); Iter; ++Iter) // 遍历 SubsystemMap
{
UClass* KeyClass = Iter.Key();
USubsystem* Subsystem = Iter.Value();
if (Subsystem->GetClass() == KeyClass)
{
Subsystem->Deinitialize(); // 清理、释放
Subsystem->InternalOwningSubsystem = nullptr;
}
}
SubsystemMap.Empty();
Outer = nullptr;
}
USubsystem* FSubsystemCollectionBase::AddAndInitializeSubsystem(UClass* SubsystemClass)
{
if (!SubsystemMap.Contains(SubsystemClass))
{
// Only add instances for non abstract Subsystems
if (SubsystemClass && !SubsystemClass->HasAllClassFlags(CLASS_Abstract))
{
// Catch any attempt to add a subsystem of the wrong type
checkf(SubsystemClass->IsChildOf(BaseType), TEXT("ClassType (%s) must be a subclass of BaseType(%s)."), *SubsystemClass->GetName(), *BaseType->GetName());
// Do not create instances of classes aren't authoritative
if (SubsystemClass->GetAuthoritativeClass() != SubsystemClass)
{
return nullptr;
} const USubsystem* CDO = SubsystemClass->GetDefaultObject<USubsystem>();
if (CDO->ShouldCreateSubsystem(Outer)) // 从CDO调用ShouldCreateSubsystem来判断是否要创建
{
USubsystem* Subsystem = NewObject<USubsystem>(Outer, SubsystemClass); //创建
SubsystemMap.Add(SubsystemClass,Subsystem); // 添加到 SubsystemMap
Subsystem->InternalOwningSubsystem = this;
Subsystem->Initialize(*this); //调用Initialize
return Subsystem;
}
}
return nullptr;
}
return SubsystemMap.FindRef(SubsystemClass);
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章