在unity中体会到过异步的好处,想着UE中肯定有实现,搜了搜,蓝鸟图不带,需要自己定义UEC++实现,继承UBlueprintAsyncActionBase 类实现。继承本基类所公开到蓝图的函数,就会携带着异步喊函数特有的右上角小时钟。

参考文章:

https://ue5wiki.com/wiki/34346/

基本思路就是,继承UBlueprintAsyncActionBase 类,然后声明多播委托,方便蓝图内执行,蓝图需要传入世界上下文,便于获取TimerManager 。然后在Activate (蓝图会自动调用本函数),根据设置的时间循环调用最终处理函数。处理函数没啥可说的,就是注意结束时要释放TimerManager 句柄和释放自己,避免崩溃。

示例代码:

.h

// 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"

/**
 * 
 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnTimerUpdate, float, Progress);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnTimerCompleted);


UCLASS()
class TEST_API UMyBlueprintAsyncActionBase : public UBlueprintAsyncActionBase
{
	GENERATED_BODY()
public:
	UPROPERTY(BlueprintAssignable)
	FOnTimerUpdate OnUpdate;

	UPROPERTY(BlueprintAssignable)
	FOnTimerCompleted OnCompleted;

	UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true", WorldContext = "WorldContextObject"))
	static UMyBlueprintAsyncActionBase* CreateTimer(UObject* WorldContextObject, float Duration);

	virtual void Activate() override;

private:
	UPROPERTY()
	UObject* WorldContextObject;
	/**总共需要的时间*/
	float TimerDuration;
	/**当前用时*/
	float CurrentTime;

	/**定时器执行*/
	void TickTimer();

	// 这里添加计时器句柄声明
	FTimerHandle TimerHandle;
};

.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "TimerManager.h"
#include "Engine/World.h"
#include "MyBlueprintAsyncActionBase.h"

UMyBlueprintAsyncActionBase* UMyBlueprintAsyncActionBase::CreateTimer(UObject* WorldContextObject, float Duration)
{
	//创建本实例
	UMyBlueprintAsyncActionBase* Action = NewObject<UMyBlueprintAsyncActionBase>();
	//获取对世界上下文的引用
	Action->WorldContextObject = WorldContextObject;
	//限制时间不菲小于1s
	Action->TimerDuration = FMath::Max(Duration, 1);
	return Action;
}
//本函数蓝图会自动执行调用
void UMyBlueprintAsyncActionBase::Activate()
{
	CurrentTime = 0.0f;
    
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
		FTimerManager& TimerManager = World->GetTimerManager();
		TimerManager.SetTimer(TimerHandle, this, &UMyBlueprintAsyncActionBase::TickTimer, 0.016f, true);
	}
}
//时间manager会根据设置间隔时间调用
void UMyBlueprintAsyncActionBase::TickTimer()
{
	//先设置本次调用时的时间
	CurrentTime += 0.016f;
    //判断是否达到要求时间
	if (CurrentTime >= TimerDuration)
	{
		//设置相同时间
		CurrentTime = TimerDuration;
        //获取时间时间管理器,使用之前获取的句柄,释放本循环
		if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
		{
			World->GetTimerManager().ClearTimer(TimerHandle);
		}
        //最后一次调用更新和调用结束委托
		OnUpdate.Broadcast(1.0f);
		OnCompleted.Broadcast();
		//调用父类函数销毁自身
		SetReadyToDestroy();
	}
	else
	{
		//没有达到则调用多播委托
		OnUpdate.Broadcast(CurrentTime / TimerDuration);
	}
}    // Fill out your copyright notice in the Description page of Project Settings.