前言

在蓝图中,我们经常能看到一些节点具备多输出执行引脚(图一)。我们知道程序执行时,按照执行流程,根据给定的条件可以出现执行分支,在蓝图中使用Branch节点可以完成。但是在设计节点时(C++中),应该如何完成节点封装后,具备多输出执行引脚?这是问题的关键。

图一
图一

首先,我们先认识下图一的节点

  • 普通C++中编写的蓝图函数节点,具有一个输出执行引脚
  • 注意,这是宏,在蓝图中编写,宏在构建时时可以加入多输入引脚与多输出引脚的。可直接在蓝图中产出
  • 在C++中构建的函数,具有多输出执行引脚
  • 在C++中构建的函数,具有多输出执行引脚

其中三条和四条的描述是一样,那是否它们是相同的呢?不然,第四个节点和第三个节点的最大区别在于:节点的右上角多了一个时钟标记。在蓝图中,这个标记代表节点是异步节点

所以节点三和四的最大区别在于执行时是否出现异步输出

C++中编写多输出执行引脚节点(非异步)

构建多输出执行引脚节点(同步)比较简单。

  • 构建枚举项,用来描述输出引脚名称
  • 编写函数,并标记为暴露到蓝图
  • 添加枚举参数,参数为引用方式
  • 增加导出枚举为执行引脚标记指令

构建枚举

c++
1
2
3
4
5
6
UENUM(BlueprintType)
enum class EBlueprintExecNodePin : uint8
{
    Success,
    Fail
};

编写函数声明

c++
1
2
UFUNCTION(BlueprintCallable, meta=(ExpandEnumAsExecs="Result"))
static void MultiExecNode(EBlueprintExecNodePin& Result);

构建函数定义

c++
1
2
3
4
5
void UMultiExecBPLibrary::MultiExecNode(EBlueprintExecNodePin& Result)
{
    //输出引脚,如果希望是Success,则直接赋值Result为Success,反之亦然
    Result = EBlueprintExecNodePin::Success;
}

C++中编写多输出执行引脚节点(异步)

异步蓝图节点构建要比其他蓝图节点编写稍微复杂些。首先在常规编码中,异步逻辑我们需要解决几个问题,第一回调函数的编写,第二在操作异步中不能释放掉调用对象,否则回调通知将会失败,第三构建异步线程,区别于当前逻辑线程。但是在蓝图中,虚幻引擎设计者简化了异步构建逻辑,将复杂性隐藏在C++中,使得我们操作的任何异步节点都非常的简单。(蓝图中是否可以构建异步节点,不在讨论范围,从角度来说,应该是不建议)

构建步骤

  • 编写C++类,继承UBlueprintAsyncActionBase类
  • 构建动态多播对象类型
  • 构建多播对象
  • 编写蓝图函数节点
  • 执行异步通知广播

编写C++类

你可以选择在创建类时继承BlueprintAsyncActionBase父类,或是在创建好的类中修改继承父类均可

图二
图二

构建动态多播类型

动态多播代理类型构建时,可以选择带有参数,或是不带有参数。可根据实际设计意图进行设计!

c++
1
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FBlueprintAsyncNodePinResult, int32, Result);

构建多播对象

c++
1
2
3
4
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnSuccess;
UPROPERTY(BlueprintAssignable)
FBlueprintAsyncNodePinResult OnFail;

注意必须加标记宏指令,否则将无法在蓝图中被应用

编写蓝图函数节点

c++
1
2
UFUNCTION(BlueprintCallable, meta = (BlueprintInternalUseOnly = "true"))
static UBlueprintAsyncNode* AsyncDelay(float Delay);

BlueprintInternalUseOnly标记指令将函数对蓝图隐藏,只用于内部操作。意图:真正的蓝图异步节点是被特殊处理的,我们不能直接将此节点暴露到蓝图(大家可以尝试去掉后,将在蓝图中看到两个AsyncDelay节点),框架会将此函数进行再次设计,以提供到蓝图中使用。

现在编译就可以在蓝图中看到暴露的节点了

图三
图三

编写异步蓝图节点当然并没有这么简单,我们只是单独阐述了过程,下篇文章(传送门)将细致讲解下如何编写异步蓝图节点

源码

头文件

c++
 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);
};

源文件

c++
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