前言
在蓝图中,我们经常能看到一些节点具备多输出执行引脚(图一)。我们知道程序执行时,按照执行流程,根据给定的条件可以出现执行分支,在蓝图中使用Branch节点可以完成。但是在设计节点时(C++中),应该如何完成节点封装后,具备多输出执行引脚?这是问题的关键。
图一
首先,我们先认识下图一的节点
- 普通C++中编写的蓝图函数节点,具有一个输出执行引脚
- 注意,这是宏,在蓝图中编写,宏在构建时时可以加入多输入引脚与多输出引脚的。可直接在蓝图中产出
- 在C++中构建的函数,具有多输出执行引脚
- 在C++中构建的函数,具有多输出执行引脚
其中三条和四条的描述是一样,那是否它们是相同的呢?不然,第四个节点和第三个节点的最大区别在于:节点的右上角多了一个时钟标记。在蓝图中,这个标记代表节点是异步节点。
所以节点三和四的最大区别在于执行时是否出现异步输出
C++中编写多输出执行引脚节点(非异步)
构建多输出执行引脚节点(同步)比较简单。
- 构建枚举项,用来描述输出引脚名称
- 编写函数,并标记为暴露到蓝图
- 添加枚举参数,参数为引用方式
- 增加导出枚举为执行引脚标记指令
构建枚举
1
2
3
4
5
6
|
UENUM(BlueprintType)
enum class EBlueprintExecNodePin : uint8
{
Success,
Fail
};
|
编写函数声明
1
2
|
UFUNCTION(BlueprintCallable, meta=(ExpandEnumAsExecs="Result"))
static void MultiExecNode(EBlueprintExecNodePin& Result);
|
构建函数定义
1
2
3
4
5
|
void UMultiExecBPLibrary::MultiExecNode(EBlueprintExecNodePin& Result)
{
//输出引脚,如果希望是Success,则直接赋值Result为Success,反之亦然
Result = EBlueprintExecNodePin::Success;
}
|
C++中编写多输出执行引脚节点(异步)
异步蓝图节点构建要比其他蓝图节点编写稍微复杂些。首先在常规编码中,异步逻辑我们需要解决几个问题,第一回调函数的编写,第二在操作异步中不能释放掉调用对象,否则回调通知将会失败,第三构建异步线程,区别于当前逻辑线程。但是在蓝图中,虚幻引擎设计者简化了异步构建逻辑,将复杂性隐藏在C++中,使得我们操作的任何异步节点都非常的简单。(蓝图中是否可以构建异步节点,不在讨论范围,从角度来说,应该是不建议)
构建步骤
- 编写C++类,继承UBlueprintAsyncActionBase类
- 构建动态多播对象类型
- 构建多播对象
- 编写蓝图函数节点
- 执行异步通知广播
编写C++类
你可以选择在创建类时继承BlueprintAsyncActionBase父类,或是在创建好的类中修改继承父类均可
图二
构建动态多播类型
动态多播代理类型构建时,可以选择带有参数,或是不带有参数。可根据实际设计意图进行设计!
1
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintAsyncNodePinResult, int32, Result);
|
构建多播对象
1
2
3
4
|
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnFail;
|
注意必须加标记宏指令,否则将无法在蓝图中被应用
编写蓝图函数节点
1
2
|
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UBlueprintAsyncNode* AsyncDelay(float Delay);
|
BlueprintInternalUseOnly标记指令将函数对蓝图隐藏,只用于内部操作。意图:真正的蓝图异步节点是被特殊处理的,我们不能直接将此节点暴露到蓝图(大家可以尝试去掉后,将在蓝图中看到两个AsyncDelay节点),框架会将此函数进行再次设计,以提供到蓝图中使用。
现在编译就可以在蓝图中看到暴露的节点了
图三
编写异步蓝图节点当然并没有这么简单,我们只是单独阐述了过程,下篇文章(传送门)将细致讲解下如何编写异步蓝图节点
源码
头文件
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
|
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintAsyncActionBase.h"
#include "BlueprintAsyncNode.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintAsyncNodePinResult, int32, Result);
/**
*
*/
UCLASS()
class UECPP_API UBlueprintAsyncNode : public UBlueprintAsyncActionBase
{
GENERATED_BODY()
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnFail;
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UBlueprintAsyncNode* AsyncDelay(float Delay);
};
|
源文件
1
2
3
4
5
6
7
8
|
// Fill out your copyright notice in the Description page of Project Settings.
#include "BlueprintAsyncNode.h"
UBlueprintAsyncNode* UBlueprintAsyncNode::AsyncDelay(float Delay)
{
return nullptr;
}
|
祝各位在虚幻中玩的愉快
虚幻版本 V4.21.2