## 引言
Subsystems 是一套可以定义、自动实例化和释放的类的框架。可以将其理解为 GamePlay 级别的 Component.
UE在4.22版本的时候开始引入Subsystems,并在4.24完善.SubSystem其实可以算是GamePlay框架基础上的一个增强功能,属于GamePlay架构的范围.
Subsystem的好处是利用它的特性可以很好的安排好对象的生命周期,也会使程序的架构更加的清晰.
## SubSystem分类及其生命周期
- **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)。
## 为什么要使用 Subsystems
- 更适用的生命周期
>**Subsystems** 的生命周期可以依存于Engine,Editor,World,LocalPlayer
- 更简
> **Subsystems** 自动创建、释放,提供 Initialize()、Deinitialize(),并且可重载
- 更模块化、更优雅、更封装、更易于维护、移植复用
> **Subsystems** 可以为不同的 Manager 创建对应的Subsystems
- 更友好的访问接口
> Subsystem 更像以全局变量的形式来访问
> 提供了 Python 脚本的访问,用于编写编辑器脚本或编写测试代码
- Subsystem 无需覆盖引擎类。
## Subsystems 的使用
### 定义C++子类
```c++
//声明定义:
UCLASS()
class HELLO_API UMyEditorSubsystem : public UEditorSubsystem
UCLASS()
class HELLO_API UMyEngineSubsystem : public UEngineSubsystem
UCLASS()
class HELLO_API UMyGameInstanceSubsystem : public UGameInstanceSubsystem
UCLASS()
class HELLO_API UMyWorldSubsystem : public UWorldSubsystem
UCLASS()
class HELLO_API UMyLocalPlayerSubsystem : public ULocalPlayerSubsystem
//注:使用UEditorSubsystem需要在Build.cs里加上EditorSubsystem模块的引用,因为这是编辑器模块
if (Target.bBuildEditor)
{
PublicDependencyModuleNames.AddRange(new string[] { "EditorSubsystem" });
}
```
添加函数和方法
```c++
UCLASS()
class HELLO_API UMyScoreSubsystem : public UGameInstanceSubsystem
{
GENERATED_BODY()
public://重载的函数,可以做一些初始化和释放操作
virtual bool ShouldCreateSubsystem(UObject* Outer) const override { return true; }
virtual void Initialize(FSubsystemCollectionBase& Collection)override;
virtual void Deinitialize()override;
public:
UFUNCTION(BlueprintCallable)
void AddScore(float delta);
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite)
float Score;
};
```
### 使用
```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>();
```
Subsystem蓝图里面也可以访问
##生命周期
各个模块的生命周期

创建对象的生命周期

## **如何用好Subsystems?**
**1. Subsystem是GamePlay级别的Component。**
**2. USubsystem只是个普通的UObject。**
**3. Subsystem是有状态的。**
**4. 尽量不要再写Manager类了。**
**5. 引擎源码里已经定义了一些Subsystem,方便 ~~抄袭~~ (学习)。**
## 参考文章
1. [《InsideUE4》GamePlay架构(十一)Subsystems - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/158717151)
2. [UE4.22 Subsystem分析 - 知乎 (zhihu.com)](https://zhuanlan.zhihu.com/p/61780989)
3. [【UE4 C++】编程子系统 Subsystem - 砥才人 - 博客园 (cnblogs.com)](https://www.cnblogs.com/shiroe/p/14819721.html)
4. [编程子系统 | 虚幻引擎文档 (unrealengine.com)](https://docs.unrealengine.com/4.26/zh-CN/ProgrammingAndScripting/Subsystems/)
5. [【技术总结】UE4中的Subsystem - 夜溅樱 - 博客园 (cnblogs.com)](https://www.cnblogs.com/yejianying/p/15029111.html)