博客
关于我
【UE4】C++ 委托、多线程
阅读量:330 次
发布时间:2019-03-04

本文共 5705 字,大约阅读时间需要 19 分钟。

UE4 中委托与任务系统实践

1. 委托机制

委托机制是 UE4 提供的一种强大的功能,允许我们将函数的执行权转移给其他组件或对象。这种机制在游戏开发中非常有用,尤其是在需要扩展或模块化代码时。

1.1 委托类型

委托可以分为多种类型,包括:

  • Object:直接使用 UObject 的成员函数
  • Lambda:使用 lambda 表达式
  • Raw:直接使用函数指针
  • SP:静态函数
  • Static:静态成员函数
  • WeakLambda:弱引用 lambda
  • UFunction:通过 UFunction 类绑定的函数

1.2 委托执行

void UDelegateObject::TestDelegate() {    UE_LOG(LogTemp, Warning, TEXT(__FUNCTION__));}

1.3 委托绑定与管理

FTestDelegate& UDelegateMaker::MakeDelegate(EDelegateType Type) {    if (Delegate.IsBound()) {        Delegate.Unbind();    }    switch (Type) {        case EDelegateType::Object:            if (UEObject == nullptr) {                UEObject = NewObject
(); } Delegate.BindUObject(UEObject, &UDelegateObject::TestDelegate); break; }}
void ADelegateInvoker::InvokeDelegate(EDelegateType Type) {    if (Maker == nullptr) {        Maker = NewObject
(); Maker->MakeDelegate(Type).ExecuteIfBound(); } else { Maker->MakeDelegate(Type).ExecuteIfBound(); }}

2. 多线程

多线程编程在游戏开发中非常重要,尤其是在需要同时处理复杂任务时。UE4 提供了丰富的多线程支持工具和功能。

3. 依赖关系结构体

依赖关系结构体用于定义任务之间的依赖关系,确保任务按正确顺序执行。

USTRUCT(BlueprintType) struct FMyTaskItem {    GENERATED_USTRUCT_BODY()public:    UPROPERTY(BlueprintReadWrite)    FString TaskName;    FString TaskName;    FGraphEventRef GraphEvent;    TGraphTask* GraphTask;    FMyTaskItem() :        TaskName(TEXT("NoName")),        GraphEvent(nullptr),        GraphTask(nullptr) {}    FMyTaskItem(FString Name, FGraphEventRef EventRef = FGraphEventRef())        : TaskName(Name),        GraphEvent(EventRef),        GraphTask(nullptr) {}    FMyTaskItem(FString Name, TGraphTask* Task = nullptr)        : TaskName(Name),        GraphEvent(nullptr),        GraphTask(Task) {}    ~FMyTaskItem() {        GraphEvent = nullptr;    }};

4. 任务定义

任务类用于定义任务的具体行为和执行方式。

class FJustPrintTask {    FString TaskName;    TArray
ChildEvents; AActor* TaskOwner;public: FJustPrintTask(FString Name, TArray
Events, AActor* Actor) : TaskName(Name), ChildEvents(Events), TaskOwner(Actor) {} ~FJustPrintTask() {} FORCEINLINE TStatId GetStatId() const { RETURN_QUICK_DECLARE_CYCLE_STAT(FJustPrintTask, STATGROUP_TaskGraphTasks); } static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; } static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; } void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) { UE_LOG(LogTemp, Log, TEXT(__FUNCTION__ " %s:Begin"), *TaskName); for (TGraphTask* Task : ChildEvents) { if (Task) { Task->Unlock(); MyCompletionGraphEvent->DontCompleteUntil(Task->GetCompletionEvent()); } } MyCompletionGraphEvent->DontCompleteUntil(TGraphTask::CreateTask().ConstructAndDispatchWhenReady(TaskName, TaskOwner)); UE_LOG(LogTemp, Log, TEXT(__FUNCTION__ " %s:End"), *TaskName); }}

5. 报告任务

报告任务用于在任务完成时触发特定事件。

class FReportTask {    FString TaskName;    AActor* TaskOwner;public:    FReportTask(FString Name, AActor* Actor) :        TaskName(Name),        TaskOwner(Actor) {}    ~FReportTask() {}    FORCEINLINE TStatId GetStatId() const {        RETURN_QUICK_DECLARE_CYCLE_STAT(FReportTask, STATGROUP_TaskGraphTasks);    }    static ENamedThreads::Type GetDesiredThread() {        return ENamedThreads::GameThread;    }    static ESubsequentsMode::Type GetSubsequentsMode() {        return ESubsequentsMode::TrackSubsequents;    }    void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) {        AMyTaskGraphActor* Actor = Cast
(TaskOwner); if (IsValid(Actor)) { Actor->OnTaskComplete(TaskName); } }}

6. Actor 与蓝图类

Actor 类用于管理任务执行。

UCLASS() class UECPP_API AMyTaskGraphActor : public AActor {    GENERATED_BODY()public:    AMyTaskGraphActor();    FMyTaskItem CreateTask(FString TaskName, const TArray
& Prerequisites, const TArray
& ChildTasks, bool DispatchWhenReady = true); FMyTaskItem CreateTaskPure(FString TaskName, bool DispatchWhenReady = true) { return CreateTask(TaskName, Empty, Empty, DispatchWhenReady); } FMyTaskItem CreateTaskWithPrerequisitesOnly(FString TaskName, const TArray
& Prerequisites, bool DispatchWhenReady = true) { return CreateTask(TaskName, Prerequisites, Empty, DispatchWhenReady); } FMyTaskItem CreateTaskWithChildTasksOnly(FString TaskName, const TArray
& ChildTasks, bool DispatchWhenReady = true) { return CreateTask(TaskName, Empty, ChildTasks, DispatchWhenReady); } UFUNCTION(BlueprintCallable) void FireTask(const FMyTaskItem& Task); UFUNCTION(BlueprintImplementableEvent) void OnTaskComplete(const FString& TaskName);}

7. 任务执行

任务执行需要按照依赖关系顺序完成。

void FJustPrintTask::DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) {    UE_LOG(LogTemp, Log, TEXT(__FUNCTION__ " %s:Begin"), *TaskName);    for (TGraphTask* Task : ChildEvents) {        if (Task) {            Task->Unlock();            MyCompletionGraphEvent->DontCompleteUntil(Task->GetCompletionEvent());        }    }    MyCompletionGraphEvent->DontCompleteUntil(TGraphTask::CreateTask().ConstructAndDispatchWhenReady(TaskName, TaskOwner));    UE_LOG(LogTemp, Log, TEXT(__FUNCTION__ " %s:End"), *TaskName);}

8. Actor 函数实现

void AMyTaskGraphActor::FireTask(const FMyTaskItem& Task) {    if (Task.GraphTask) {        UE_LOG(LogTemp, Log, TEXT("Task[%s] Fire."), *Task.TaskName));        Task.GraphTask->Unlock();    }}

通过以上内容,可以看出 UE4 提供了强大的任务和委托系统,能够有效管理复杂任务流程和依赖关系。

转载地址:http://ibuh.baihongyu.com/

你可能感兴趣的文章
MySQL中UPDATE语句的神奇技巧,让你操作数据库如虎添翼!
查看>>
Mysql中varchar类型数字排序不对踩坑记录
查看>>
MySQL中一条SQL语句到底是如何执行的呢?
查看>>
MySQL中你必须知道的10件事,1.5万字!
查看>>
MySQL中使用IN()查询到底走不走索引?
查看>>
Mysql中使用存储过程插入decimal和时间数据递增的模拟数据
查看>>
MySql中关于geometry类型的数据_空的时候如何插入处理_需用null_空字符串插入会报错_Cannot get geometry object from dat---MySql工作笔记003
查看>>
mysql中出现Incorrect DECIMAL value: '0' for column '' at row -1错误解决方案
查看>>
mysql中出现Unit mysql.service could not be found 的解决方法
查看>>
mysql中出现update-alternatives: 错误: 候选项路径 /etc/mysql/mysql.cnf 不存在 dpkg: 处理软件包 mysql-server-8.0的解决方法(全)
查看>>
Mysql中各类锁的机制图文详细解析(全)
查看>>