当前位置:   article > 正文

UE C++进阶 | 异步_uec++

uec++

UE C++进阶 | 异步

潜伏事件

  • 在UE的蓝图中存在一种可以实现异步执行的节点,
  • 想要去实现我们自己的异步节点,首先我们需要了解FPendingLatentAction

Unreal - FPendingLatentAction

  • 中文翻译来说应该是待定的潜伏动作。
  • 我们先来看看它的源码。
  • 存在几个虚函数,看起来UpdateOperation是关键。
  • Response.DoneIf(true);是该动作标志着工作做完了调用的,相当与需要 destory了。
class ENGINE_API FPendingLatentAction
{
public:
    // 构造
	FPendingLatentAction()
	{
	}

    // 析构
	virtual ~FPendingLatentAction()
	{
	}

	// 动作完成后传入true,然后就会被销毁。
	virtual void UpdateOperation(FLatentResponse& Response)
	{
		Response.DoneIf(true);
	}

	/* 让潜伏的动作知道,产生它的对象已经被垃圾回收了。
     * 并且该动作将被销毁(不再有UpdateOperation的调用,并且CallbackTarget已经是NULL)
     * 只有当对象在动作完成前离开时才会被调用。
    */
	virtual void NotifyObjectDestroyed() {}

	virtual void NotifyActionAborted() {}
#if WITH_EDITOR
	// 返回对潜伏操作当前状态的可读描述。
	virtual FString GetDescription() const;
#endif
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Unreal - Delay节点

  • 例如我们常用的Delay节点,当输入执行节点被触发后,输出执行节点直到对应时间耗尽后才会触发。
    Delay节点
  • 让我们先分析一下源码。

FDelayAction

  • 继承自FPendingLatentAction
  • 声明有几个变量,其中有几个参数是为LatentInfo服务的。
  • 重写了UpdateOperation,这个函数因为相当于 Tick函数,所以可以写一些计时的业务逻辑。
  • 重写了GetDescription,为了使得在蓝图调试过程中打印在节点上。
    Delay节点的打印
class FDelayAction : public FPendingLatentAction
{
public:
	float TimeRemaining;            // 业务变量
	FName ExecutionFunction;        // LatentInfo服务
	int32 OutputLink;               // LatentInfo服务
	FWeakObjectPtr CallbackTarget;  // LatentInfo服务

    // 有参构造
	FDelayAction(float Duration, const FLatentActionInfo& LatentInfo)
		: TimeRemaining(Duration)
		, ExecutionFunction(LatentInfo.ExecutionFunction)
		, OutputLink(LatentInfo.Linkage)
		, CallbackTarget(LatentInfo.CallbackTarget)
	{
	}

    // 业务逻辑
	virtual void UpdateOperation(FLatentResponse& Response) override
	{   
        // 定时器
		TimeRemaining -= Response.ElapsedTime();
        // 完成与触发,如果想要深入理解可以去看FLatentResponse,这个函数相当于DoneIf + TriggerLink。
		Response.FinishAndTriggerIf(TimeRemaining <= 0.0f, ExecutionFunction, OutputLink, CallbackTarget);
	}

#if WITH_EDITOR
    // 蓝图调试过程中打印
	virtual FString GetDescription() const override
	{
		static const FNumberFormattingOptions DelayTimeFormatOptions = FNumberFormattingOptions()
			.SetMinimumFractionalDigits(3)
			.SetMaximumFractionalDigits(3);
		return FText::Format(NSLOCTEXT("DelayAction", "DelayActionTimeFmt", "Delay ({0} seconds left)"), FText::AsNumber(TimeRemaining, &DelayTimeFormatOptions)).ToString();
	}
#endif
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

函数声明:

UFUNCTION(BlueprintCallable, Category="Utilities|FlowControl", meta=(Latent, WorldContext="WorldContextObject", LatentInfo="LatentInfo", Duration="0.2", Keywords="sleep"))
static void	Delay(const UObject* WorldContextObject, float Duration, struct FLatentActionInfo LatentInfo );
  • 1
  • 2
  • 头文件基本信息:
    • 基类 - UBlueprintFunctionLibrary
      • UKismetSystemLibrary- \\UE_5.1\Engine\Source\Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h
        • ↳ 类静态函数 Delay
  • 用法:执行一个有延迟的潜伏动作(以秒为单位指定),在其倒计时时再次调用将被忽略。
  • 宏标记解析:
    • BlueprintCallable: 该函数可以在蓝图或关卡蓝图图表中执行。
    • Category: 指定函数在编辑器中的显示分类层级。
    • meta
      • Lantent: 表示潜在的行动。
      • WorldContext = “WorldContextObject”: 用来指示哪个参数确定操作正在发生的世界。
      • LatentInfo = “LatentInfo”: 指示哪个参数是LatentInfo参数。
      • Duration = “0.2”: 默认值。
      • Keywords = “sleep”: 指定搜索此函数时可以使用的一组关键字。
  • 参数:
    • WorldContextObject - 世界上下文,已经由meta绑定。
    • Duration - 延迟的长度(以秒为单位)
    • LatentInfo - 潜在的动作信息,已经由meta绑定。

函数实现:

void UKismetSystemLibrary::Delay(const UObject* WorldContextObject, float Duration, FLatentActionInfo LatentInfo )
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
        // 去获得潜伏动作管理器
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); 
        // 从潜伏动作管理器查找该节点位置是否已经存在此类动作位置
		if (LatentActionManager.FindExistingAction<FDelayAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == NULL)
		{
            // 找不到就加入新的潜伏动作
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FDelayAction(Duration, LatentInfo));
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

案例 - SustainedAxisTriggerAction (持续轴映射触发动作)

  • 到这我们大致了解了需要了解虚幻的潜伏动作,开始写我们自己的异步节点。
  • 这是一个我自己工作中实践出来的功能。
  • 它可以接受手柄的Axis值然后进行连续触发动作。
    • 具体:在接收手柄输入后,进行第一次触发,如果持续按住的状态下,在一定时间过后开始进行连续触发。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 源码展示
// Copyright(c) 2023 TangYijun All rights reserved.

#pragma once

#include "LatentActions.h"
#include "Misc/EnumRange.h"

// 轴输入的几个阶段
UENUM(BlueprintType)
enum class ESustainedAxisState : uint8
{
	EPress,
	ELowPulseInterval,
	ELowPulseTrigger,
	EHighPulseInterval,
	ELowToHighTransition,
	EHighPulseTrigger,
	ECount
};

// 轴映射的正反
UENUM(BlueprintType)
enum class ESustainedAxisExec : uint8
{
	EPositive,
	ENegative
};

// 创建枚举的计数
ENUM_RANGE_BY_COUNT(ESustainedAxisState, ESustainedAxisState::ECount);

// 基类
class FSustainedAxisTriggerActionBase : public FPendingLatentAction
{
public:
	float Axis;             // 轴输入
	float AxisThreshold;    // 创建枚举的计数

	FName ExecutionFunction;
	int32 OutputLink;
	FWeakObjectPtr CallbackTarget;

	ESustainedAxisExec& ExecRef;    // 节点的输出执行线

protected:
	TBitArray<> AxisStateBits;      // 轴输入的激活状态集
	TMap<ESustainedAxisState, float> CountMap;  // 计时器
	bool bIsPress;  // 是否摁下
public:
    //构造
	FSustainedAxisTriggerActionBase(float Axis, float AxisThreshold, const FLatentActionInfo& LatentInfo, ESustainedAxisExec& AxisExec)
		: Axis(Axis)
		, AxisThreshold(AxisThreshold)
		, ExecutionFunction(LatentInfo.ExecutionFunction)
		, OutputLink(LatentInfo.Linkage)
		, CallbackTarget(LatentInfo.CallbackTarget)
		, ExecRef(AxisExec)
	{
        // 初始化状态集
		AxisStateBits = TBitArray<>(false, uint8(ESustainedAxisState::ECount));
	}

    // 业务更新
	virtual void UpdateOperation(FLatentResponse& Response) override
	{
        // 判断轴输入
		bIsPress = Axis > AxisThreshold || Axis < -AxisThreshold;
        
		UpdateDoneIf(Response); // 更新执行线走向
		UpdateTimer(Response);  // 更新计时器
	}

protected:
	FORCEINLINE bool IsTimeOver(const ESustainedAxisState& State)
	{
		return CountMap[State] <= 0.f && AxisStateBits[uint8(State)];
	}

	FORCEINLINE void EnterState(const ESustainedAxisState& State)
	{
		AxisStateBits[uint8(State)] = true;
	}

	FORCEINLINE void ExitState(const ESustainedAxisState& State)
	{
		AxisStateBits[uint8(State)] = false;
	}

	FORCEINLINE void UpdateTimer(FLatentResponse& Response)
	{
		for (ESustainedAxisState AxisState : TEnumRange<ESustainedAxisState>())
		{
			if (CountMap.Contains(AxisState))
			{
				if (AxisStateBits[uint8(AxisState)])
				{
					CountMap[AxisState] -= Response.ElapsedTime();
				}
			}
		}
	}

	FORCEINLINE void UpdateDoneIf(FLatentResponse& Response)
	{
		if (!bIsPress)
		{
			Response.DoneIf(!bIsPress);
		}
		else
		{
			if (Axis > AxisThreshold)
			{
				ExecRef = ESustainedAxisExec::EPositive;
			}
			else if (Axis < -AxisThreshold)
			{
				ExecRef = ESustainedAxisExec::ENegative;
			}
		}
	}

};

// 一阶段持续轴触发动作,就是按下后一定时间开始保持持续触发状态。
class FOneStepSustainedAxisTriggerAction : public FSustainedAxisTriggerActionBase
{
public:

	float PulseTriggerTime; // 脉冲触发时间 - 触发频率。
	float PulseIntervalTime;// 脉冲间隔时间 - 从触发第一次到开始持续触发状态的间隔时间。

	FOneStepSustainedAxisTriggerAction(float Axis, float AxisThreshold, float PulseTriggerTime, float PulseIntervalTime,
		const FLatentActionInfo& LatentInfo, ESustainedAxisExec& AxisExec)
		: FSustainedAxisTriggerActionBase(Axis, AxisThreshold, LatentInfo, AxisExec)
		, PulseTriggerTime(PulseTriggerTime)
		, PulseIntervalTime(PulseIntervalTime)
	{
        // 增加这两种状态的定时器
		CountMap.Emplace(ESustainedAxisState::ELowPulseInterval, PulseIntervalTime);
		CountMap.Emplace(ESustainedAxisState::ELowPulseTrigger, PulseTriggerTime);
	}

	virtual void UpdateOperation(FLatentResponse& Response) override
	{
		FSustainedAxisTriggerActionBase::UpdateOperation(Response);
        // 简易状态机
		if (bIsPress && !AxisStateBits[uint8(ESustainedAxisState::EPress)])
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			EnterState(ESustainedAxisState::EPress);
			EnterState(ESustainedAxisState::ELowPulseInterval);
		}

		if (IsTimeOver(ESustainedAxisState::ELowPulseInterval))
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			ExitState(ESustainedAxisState::ELowPulseInterval);
			EnterState(ESustainedAxisState::ELowPulseTrigger);
		}

		if (IsTimeOver(ESustainedAxisState::ELowPulseTrigger))
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			CountMap[ESustainedAxisState::ELowPulseTrigger] = PulseTriggerTime;
		}
	}
};

class FTwoStepSustainedAxisTriggerAction : public FSustainedAxisTriggerActionBase
{
public:
	float LowPulseTriggerTime;  // 低频脉冲触发时间 - 阶段一触发频率。
	float LowPulseIntervalTime; // 低频脉冲间隔时间 - 从触发第一次到开始阶段一的间隔时间。
	float HighPulseTriggerTime; // 高频脉冲触发时间 - 阶段二触发频率。
	float HighPulseIntervalTime;// 高频脉冲间隔时间 - 从阶段一到阶段二的间隔时间。

	FTwoStepSustainedAxisTriggerAction(float Axis, float AxisThreshold, float LowPulseTriggerTime,
		float LowPulseIntervalTime, float HighPulseTriggerTime, float HighPulseIntervalTime,
		const FLatentActionInfo& LatentInfo, ESustainedAxisExec& AxisExec)
		: FSustainedAxisTriggerActionBase(Axis, AxisThreshold, LatentInfo, AxisExec)
		, LowPulseTriggerTime(LowPulseTriggerTime)
		, LowPulseIntervalTime(LowPulseIntervalTime)
		, HighPulseTriggerTime(HighPulseTriggerTime)
		, HighPulseIntervalTime(HighPulseIntervalTime)
	{
        // 增加这四种状态的定时器
		CountMap.Emplace(ESustainedAxisState::ELowPulseInterval, LowPulseIntervalTime);
		CountMap.Emplace(ESustainedAxisState::ELowPulseTrigger, LowPulseTriggerTime);
		CountMap.Emplace(ESustainedAxisState::EHighPulseInterval, HighPulseIntervalTime);
		CountMap.Emplace(ESustainedAxisState::EHighPulseTrigger, HighPulseTriggerTime);
	}

	virtual void UpdateOperation(FLatentResponse& Response) override
	{
		FSustainedAxisTriggerActionBase::UpdateOperation(Response);

        // 简易状态机
		if (bIsPress && !AxisStateBits[uint8(ESustainedAxisState::EPress)])
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			EnterState(ESustainedAxisState::EPress);
			EnterState(ESustainedAxisState::ELowPulseInterval);
		}

		if (IsTimeOver(ESustainedAxisState::ELowPulseInterval))
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			ExitState(ESustainedAxisState::ELowPulseInterval);
			EnterState(ESustainedAxisState::ELowPulseTrigger);
			EnterState(ESustainedAxisState::EHighPulseInterval);
		}

		if (IsTimeOver(ESustainedAxisState::ELowPulseTrigger))
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			CountMap[ESustainedAxisState::ELowPulseTrigger] = LowPulseTriggerTime;
			if (AxisStateBits[uint8(ESustainedAxisState::ELowToHighTransition)])
			{
				EnterState(ESustainedAxisState::EHighPulseTrigger);
				ExitState(ESustainedAxisState::ELowPulseTrigger);
			}
		}

		if (IsTimeOver(ESustainedAxisState::EHighPulseInterval))
		{
			if (CountMap[ESustainedAxisState::ELowPulseTrigger] <= 0)
			{
				EnterState(ESustainedAxisState::EHighPulseTrigger);
			}
			else
			{
				EnterState(ESustainedAxisState::ELowToHighTransition);
			}
			ExitState(ESustainedAxisState::EHighPulseInterval);
		}

		if (IsTimeOver(ESustainedAxisState::EHighPulseTrigger))
		{
			Response.TriggerLink(ExecutionFunction, OutputLink, CallbackTarget);
			CountMap[ESustainedAxisState::EHighPulseTrigger] = HighPulseTriggerTime;
		}
	}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 源码展示 (LatentFunctionLibrary.h)
// Copyright(c) 2023 TangYijun All rights reserved.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "PendingLatentAction/SustainedAxisTriggerAction.h"
#include "LatentFunctionLibrary.generated.h"

UCLASS()
class HECATONCHEIRES_API ULatentFunctionLibrary : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
public:
	UFUNCTION(BlueprintCallable, Category = "UI|Trigger", meta = (ExpandEnumAsExecs = "AxisExec", Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo"))
	static void OneStepSustainedAxisTrigger(const UObject* WorldContextObject, ESustainedAxisExec& AxisExec, float Axis, float AxisThreshold, float PulseTriggerTime,
		float PulseIntervalTime, FLatentActionInfo LatentInfo);
	UFUNCTION(BlueprintCallable, Category = "UI|Trigger", meta = (ExpandEnumAsExecs = "AxisExec", Latent, WorldContext = "WorldContextObject", LatentInfo = "LatentInfo"))
	static void TwoStepSustainedAxisTrigger(const UObject* WorldContextObject, ESustainedAxisExec& AxisExec, float Axis, float AxisThreshold, float LowPulseTriggerTime,
		float LowPulseIntervalTime, float HighPulseTriggerTime, float HighPulseIntervalTime, FLatentActionInfo LatentInfo);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 源码展示 (LatentFunctionLibrary.cpp)
// Copyright(c) 2023 TangYijun All rights reserved.

#include "FunctionLibrary/LatentFunctionLibrary.h"
#include "Engine/LatentActionManager.h"

void ULatentFunctionLibrary::OneStepSustainedAxisTrigger(const UObject* WorldContextObject, ESustainedAxisExec& AxisExec, float Axis, float AxisThreshold,
	float PulseTriggerTime, float PulseIntervalTime, FLatentActionInfo LatentInfo)
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
		FOneStepSustainedAxisTriggerAction* Action = LatentActionManager.FindExistingAction<FOneStepSustainedAxisTriggerAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
		if (!Action)
		{
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FOneStepSustainedAxisTriggerAction(Axis,
				AxisThreshold, PulseTriggerTime, PulseIntervalTime, LatentInfo, AxisExec));
		}
		else
		{
			Action->Axis = Axis;
		}
	}
}

void ULatentFunctionLibrary::TwoStepSustainedAxisTrigger(const UObject* WorldContextObject, ESustainedAxisExec& AxisExec, float Axis, float AxisThreshold,
	float LowPulseTriggerTime, float LowPulseIntervalTime, float HighPulseTriggerTime, float HighPulseIntervalTime, FLatentActionInfo LatentInfo)
{
	if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull))
	{
		FLatentActionManager& LatentActionManager = World->GetLatentActionManager();
		FTwoStepSustainedAxisTriggerAction* Action = LatentActionManager.FindExistingAction<FTwoStepSustainedAxisTriggerAction>(LatentInfo.CallbackTarget, LatentInfo.UUID);
		if (!Action)
		{
			LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, new FTwoStepSustainedAxisTriggerAction(Axis,
				AxisThreshold, LowPulseTriggerTime, LowPulseIntervalTime, HighPulseTriggerTime, HighPulseIntervalTime, LatentInfo, AxisExec));
		}
		else
		{
			Action->Axis = Axis;
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

定时器

FTimerManager

绑定定时器
  • BindLambda.
FTimerHandle TimerHandle;
const auto Exec = []()
{
	// Implement...
};
World->GetTimerManager().SetTimer(TimerHandle, Exec, 1.0f, false);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • BindFunction.
FTimerHandle TimerHandle;
World->GetTimerManager().SetTimer(TimeHandler, this, &ThisClass::TimerFunction, 1.0f, false);
  • 1
  • 2
清除定时器
GetWorld()->GetTimerManager().ClearTimer(TimeHandler);
  • 1
定时器的模式
延迟模式
  • 延迟2秒后执行一次 Exec()。
World->GetTimerManager().SetTimer(TimerHandle, Exec, 2.0f, false);
  • 1
循环模式
  • 自设置时起就执行一次 Exec(),并开始每隔1秒就执行一次 Exec(),永不停歇,直到定时器被清除。
World->GetTimerManager().SetTimer(TimerHandle, Exec, 2.0f, true, 0.0f);
  • 1
延迟循环模式
  • 延迟2秒后第一次执行 Exec(),之后每隔1秒就执行一次 Exec(),永不停歇,直到定时器被清除。
World->GetTimerManager().SetTimer(TimerHandle, Exec, 1.0f, true, 2.0f);
  • 1

异步蓝图节点

Unreal - UBlueprintAsyncActionBase

(TODO)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/895000
推荐阅读
相关标签
  

闽ICP备14008679号