使用方法
-
继承 UBlueprintAsyncActionBase
-
成员函数 Activate 用于内部触发委托绑定的事件
-
成员函数 RegisterWithGameInstance 允许将该对象注册到 GameInstance,防止GC
-
注册后,调用成员方法 SetReadyToDestroy 销毁、释放,从 GameInstance 注销
-
声明静态函数
-
需要动态多播委托,作为多个输出节点
代码实现
头文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "MyBlueprintAsyncActionBase.generated.h"
/**
*
*/
UCLASS()
class MYUNREALCPP_API AAsyncTickActor : public AActor
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintReadWrite)
TArray<int32>CountdownNums;
};
// 定义委托类型
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FResultHandleDelegate, int32, Result);
UCLASS()
class MYUNREALCPP_API UMyBlueprintAsyncActionBase : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
public:
UMyBlueprintAsyncActionBase(){;}
~UMyBlueprintAsyncActionBase(){;}
// 自定义的异步蓝图节点
UFUNCTION(BlueprintCallable, meta = (WorldContext = "WorldContextObject"), Category = "MyBPAsyncAction")
static UMyBlueprintAsyncActionBase* LatentCountdown(UObject* WorldContextObject, AAsyncTickActor* AsyncTickActor, int32 StartNum);
public:
//输出节点
UPROPERTY(BlueprintAssignable)
FResultHandleDelegate OnSucceeded;
//输出节点
UPROPERTY(BlueprintAssignable)
FResultHandleDelegate OnFailed;
private:
FTimerHandle TimerHandle;
protected:
virtual void Activate() override;
};
源文件
// Fill out your copyright notice in the Description page of Project Settings.
#include "Test/MyBlueprintAsyncActionBase.h"
void UMyBlueprintAsyncActionBase::Activate()
{
// 开新的线程,测试 Activate 调用情况
Async(EAsyncExecution::ThreadPool, [&]()
{
UE_LOG(LogTemp, Warning, TEXT("Start Delay 2s."));
FPlatformProcess::Sleep(2.0f);
UE_LOG(LogTemp, Warning, TEXT("Delay Finished."));
});
}
UMyBlueprintAsyncActionBase* UMyBlueprintAsyncActionBase::LatentCountdown(UObject* WorldContextObject, AAsyncTickActor* AsyncTickActor, int32 StartNum)
{
if (WorldContextObject == nullptr)
{
UE_LOG(LogTemp, Warning, TEXT("Invalid WorldContextObject."));
return nullptr;
}
UMyBlueprintAsyncActionBase* TestLatentNode = NewObject<UMyBlueprintAsyncActionBase>();
auto CountdownFunc = [&, TestLatentNode, WorldContextObject, AsyncTickActor, StartNum]() {
if (IsValid(AsyncTickActor))
{
if (AsyncTickActor->CountdownNums.Num() == StartNum)
{
TestLatentNode->OnSucceeded.Broadcast(1);
WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(TestLatentNode->TimerHandle);
TestLatentNode->SetReadyToDestroy();
UE_LOG(LogTemp, Warning, TEXT(" Countdown Completed."));
}
else
{
int32 length = AsyncTickActor->CountdownNums.Num();
AsyncTickActor->CountdownNums.Add(length + 1);
UE_LOG(LogTemp, Warning, TEXT(" Counting down... %d"), length + 1);
}
}
else
{
TestLatentNode->OnFailed.Broadcast(-1);
WorldContextObject->GetWorld()->GetTimerManager().ClearTimer(TestLatentNode->TimerHandle);
UE_LOG(LogTemp, Warning, TEXT("Invalid AsyncTickActor."));
FFrame::KismetExecutionMessage(TEXT("Invalid AsyncTickActor"), ELogVerbosity::Error);
}
};
WorldContextObject->GetWorld()->GetTimerManager().SetTimer(TestLatentNode->TimerHandle, FTimerDelegate::CreateLambda(CountdownFunc), 1.0f, true);
UE_LOG(LogTemp, Warning, TEXT("Countdown Starting."));
return TestLatentNode;
}