UE5 C++ Subsystem 和 多线程

发布于:2024-12-18 ⋅ 阅读:(84) ⋅ 点赞:(0)

一.Subsystem先做一个简单的介绍,其实可以去看大钊的文章有一篇专门讲这个的。

GamePlay框架基础上的一个增强功能,属于GamePlay架构的范围。Subsystems是一套可以定义自动实例化和释放的类的框架。这个框架允许你从5类里选择一个来定义子类(只能在C++定义):

有点像“全局变量”,也有点像是静态蓝图函数(如GetGameInstance),可以方便的在蓝图的各个地方调用。Subsystems真正的威力其实远不止这点手头上的便利,而在于接下来要谈的引擎帮你自动处理的部分。说实话,我还没理解到这个层次上

Subsystem对象的生命周期取决于其依存的Outer对象的生命周期,随着Outer对象的创建而创建,随着Outer对象的销毁而销毁。而选择依存哪种Outer对象,就是选择哪种Subsystem生命周期,靠的就是选择继承于哪个Subsystem基类。

二.简单创建一个单例。

重写父类的父类USubsystem的这三个函数:

	virtual bool ShouldCreateSubsystem(UObject* Outer) const override;

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

	/** Implement this for deinitialization of instances of the system */
	virtual void Deinitialize() override;

以此来看它的生命周期

bool UMyGameInstanceSubsystem::ShouldCreateSubsystem(UObject* Outer) const
{
	return true;
}

void UMyGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp,Warning,TEXT("Initialize"));
	//myRunnable = 
	Ins = this;
}

void UMyGameInstanceSubsystem::Deinitialize()
{
	Super::Deinitialize();
	UE_LOG(LogTemp, Warning, TEXT("Deinitialize"));
}

接着重点来了,定义成单例。经典的单例写法,一个static指针,一个staic获得自己的函数。

public:
	static  UMyGameInstanceSubsystem* Ins;  //static 不能加反射
	UFUNCTION(BlueprintCallable,Category = "MyGameInstanceSubsystem")
	static UMyGameInstanceSubsystem* Get();

这个指针,在CPP里面,开头需要初始化空。不然会报错,因为static的指针在类对象生成之前。

然后,在这个线程初始化完成后,将这个Ins 指针指向自己。

void UMyGameInstanceSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
	UE_LOG(LogTemp,Warning,TEXT("Initialize"));
	//myRunnable = 
	Ins = this;
}

在Get()函数里,返回Ins这种指向的单例子系统。这样UFUNCTION蓝图,和C++里都能很方便获得。

UMyGameInstanceSubsystem* UMyGameInstanceSubsystem::Get()
{
	UE_LOG(LogTemp, Warning, TEXT("Get Subsystem"));
	return Ins;
}

三.在单例里面,写线程

1.先把线程类准备好,不继承UE的类,头文件如下。我觉得可以暂时理解为线程的生命周期,是由代码确定的,而不是直接和UE的其它类保持相同。

#include "CoreMinimal.h"
#include "HAL/Runnable.h" 
#include "HAL/ThreadSafeBool.h" //线程安全

创建一个空的类,在类里面继承FRunnable。类的名字也需要改为F开头。童谣需要重写FRunnable的四个函数。

class MYPROJECT_API FMyRunable:public FRunnable //
{
public:
	FMyRunable();
	~FMyRunable();
	FMyRunable(FString InThreadName);

	virtual bool Init()override;

	virtual uint32 Run() override;
	virtual void Stop() override;
	virtual void Exit() override;

	FString ThreadName;
private:
	bool IsRunning;
};

2.线程的实现如下

简单的输出日志

	UFUNCTION(BlueprintCallable, Category = "MyGameInstanceSubsystem")
	void StartThread();
	UFUNCTION(BlueprintCallable, Category = "MyGameInstanceSubsystem")
	void StopThread();


FMyRunable::FMyRunable()
{
	UE_LOG(LogTemp, Warning, TEXT("gouzaohanshu"));
}

FMyRunable::~FMyRunable()
{
	UE_LOG(LogTemp, Warning, TEXT("xigouhanshu"));
}

FMyRunable::FMyRunable(FString InThreadName)
	:ThreadName(InThreadName)
{
	UE_LOG(LogTemp, Warning, TEXT("gouzaohanshu1"));
}

bool FMyRunable::Init()
{
	return true;
}

uint32 FMyRunable::Run()
{
	IsRunning = true;
	return uint32();
}

void FMyRunable::Stop()
{
	IsRunning = false;
}

void FMyRunable::Exit()
{
	UE_LOG(LogTemp, Warning, TEXT("Exit Thread"));
}

3.接着需要将子系统和线程联系起来

在GameInstance里面声明

	//TSharedPtr<MyRunable> ref;
protected:
	TSharedPtr<FMyRunable> myRunnable;
	FRunnableThread* MyRunnableThread;

在GameInstance里需要实现,开启线程。这里首先创建一个myRunable对象,其次再开启线程,并关联到这个对象。这个时候,线程对象会自动开始跑自己的Run函数,因为它被开启了。

void UMyGameInstanceSubsystem::StartThread()
{
	myRunnable = MakeShared<FMyRunable>(TEXT("MyRunnable"));  //创建指针
	MyRunnableThread = FRunnableThread::Create(myRunnable.Get(),*(myRunnable->ThreadName)); //创建线程程
	UE_LOG(LogTemp, Warning, TEXT("Start Thread"));
}

现在我们添加myRunable里的Run的内容,让他循环输出,每三秒一次

uint32 FMyRunable::Run()
{
	IsRunning = true;
	while (IsRunning)
	{
		FPlatformProcess::Sleep(3.0);
		UMyGameInstanceSubsystem* Instance = UMyGameInstanceSubsystem::Get();
		if (Instance)
		{
			UE_LOG(LogTemp, Warning, TEXT("Run Thread"));
		}
	}
	return uint32();
}

如果想让它停止,就在GameInstanceSubsystem里实现。

void UMyGameInstanceSubsystem::StopThread()
{
	if(myRunnable.IsValid())
	{
		myRunnable->Stop();
	}
	UE_LOG(LogTemp, Warning, TEXT("Stop Thread"));
}
void FMyRunable::Stop()
{
	IsRunning = false;
}


网站公告

今日签到

点亮在社区的每一天
去签到