UE蓝图 分支(Branch)节点和源码

news2025/1/17 21:39:04

系列文章目录

UE蓝图 Cast节点和源码
UE蓝图 分支(Branch)节点和源码


文章目录

  • 系列文章目录
  • 一、分支节点功能
  • 二、分支节点用法
  • 三、分支节点使用场景
  • 四、分支节点实现过程
  • 五、分支节点相关源码


一、分支节点功能

在这里插入图片描述

在Unreal Engine(UE)的蓝图中,Branch节点是一个非常重要的的逻辑控制节点,它允许你根据某个条件(Condition)的真假来执行不同的逻辑路径。这个节点在编程中相当于一个if-else语句,用于控制程序的流程。

在UE蓝图中使用Branch节点时,你通常会连接一个布尔值(Boolean)到节点的Condition引脚。这个布尔值可以是来自其他节点的输出,也可以是一个固定的值(如true或false)。然后,你可以在IfTrueIfFalse两个输出引脚上连接你想要执行的操作或逻辑。

  • 如果Condition引脚接收到的值为true,那么从IfTrue引脚引出的逻辑将会被执行。
  • 如果Condition引脚接收到的值为false,那么从IfFalse引脚引出的逻辑将会被执行。

这样,你就可以根据不同的条件来动态地改变你的游戏或应用程序的行为。这在制作交互式游戏、响应玩家输入、处理不同的事件场景等方面都非常有用。


二、分支节点用法

在Unreal Engine(UE)的蓝图中使用分支节点,你需要按照以下步骤进行操作:

  1. 创建分支节点:首先,在蓝图中右击,选择“流程控制” -> “分支”来创建一个分支节点。这将添加一个具有条件(Condition)输入和两个输出引脚(True和False)的节点。

  2. 连接条件输入:接下来,你需要将一个布尔值或表达式连接到分支节点的Condition输入引脚。这个布尔值或表达式的结果将决定分支节点执行哪个分支。

  3. 设置True分支:在分支节点的True输出引脚上,你可以连接任何你希望在条件为真时执行的逻辑或操作。这可以是一个函数调用、变量设置、另一个逻辑节点等。

  4. 设置False分支:同样,在分支节点的False输出引脚上,你可以连接在条件为假时应该执行的逻辑或操作。

  5. 编译和测试:完成节点设置后,确保你的蓝图没有编译错误,并在游戏中测试分支节点的行为。你可以通过改变连接到Condition引脚的值来验证分支是否正确执行。

  6. 调试和优化:如果分支节点的行为不符合预期,使用UE的调试工具来查找问题并进行相应的调整。

记住,分支节点的行为完全依赖于Condition引脚的输入值。确保你的条件表达式正确无误,并且连接到正确的引脚。此外,分支节点通常用于控制程序的流程,因此确保你的逻辑流程符合你的游戏或应用程序的需求。

三、分支节点使用场景

Unreal Engine(UE)蓝图中的分支节点(Branch Node)具有广泛的应用场景,主要用于实现条件逻辑,让游戏或应用程序的行为能够根据不同的条件进行变化。以下是一些具体的应用场景示例:

  1. 玩家交互与决策:在游戏中,分支节点可以用于处理玩家的交互和决策。例如,玩家面对一个选择时,分支节点可以根据玩家的选择(由输入事件触发)来执行不同的游戏逻辑,如不同的对话路径、任务结果或游戏事件。

  2. AI行为树:在AI行为树中,分支节点用于决定AI角色的行为。根据环境状态、目标优先级或其他条件,分支节点可以帮助AI选择最合适的行动方案,如巡逻、搜寻、攻击或逃跑。

  3. 游戏事件与状态管理:在游戏逻辑中,分支节点可用于处理游戏事件和状态的变化。例如,根据玩家的当前状态(如健康值、能量水平或武器状态)来执行不同的游戏逻辑,如允许或禁止某些操作,或触发特定的事件。

  4. 条件性任务执行:在任务或剧情流程中,分支节点允许开发者根据任务条件(如任务状态、玩家行为或环境变量)来执行不同的任务步骤或结果。这有助于创建更丰富、更灵活的剧情体验。

  5. 网络和多玩家交互:在多人在线游戏中,分支节点可以用于处理网络状态、玩家状态或其他玩家的行为。根据这些条件,游戏可以执行不同的逻辑,如同步玩家状态、处理网络延迟或处理玩家间的交互。

  6. 动态环境交互:在动态环境中,分支节点可用于处理与环境的交互。例如,根据物体的状态(如是否被破坏、是否被拾取等)来执行不同的逻辑,如改变环境状态、播放音效或触发其他事件。

在这些场景中,分支节点的灵活性使得开发者能够根据游戏或应用程序的具体需求来创建复杂的逻辑结构,从而实现更加丰富和动态的用户体验。通过组合不同的节点类型和条件判断,开发者可以构建出各种复杂的条件分支逻辑。

四、分支节点实现过程

  • 创建输入输出引脚
public void allocateDefaultPins() {
    createPin(EGPD_Input, EdGraphSchemaK2.PC_Exec, EdGraphSchemaK2.PN_Execute);
    EdGraphPin conditionPin = createPin(EGPD_Input, EdGraphSchemaK2.PC_Boolean, EdGraphSchemaK2.PN_Condition);
    EdGraphPin truePin = createPin(EGPD_Output, EdGraphSchemaK2.PC_Exec, EdGraphSchemaK2.PN_Then);
    EdGraphPin falsePin = createPin(EGPD_Output, EdGraphSchemaK2.PC_Exec, EdGraphSchemaK2.PN_Else);
    super.allocateDefaultPins();
}
  • 调用KCHandler_Branch 注册net

  • 编译创建分支Statement

// First skip the if, if the term is false
FBlueprintCompiledStatement& SkipIfGoto = Context.AppendStatementForNode(Node);
SkipIfGoto.Type = KCST_GotoIfNot;
SkipIfGoto.LHS = *CondTerm;
Context.GotoFixupRequestMap.Add(&SkipIfGoto, ElsePin);

// Now go to the If branch
FBlueprintCompiledStatement& GotoThen = Context.AppendStatementForNode(Node);
GotoThen.Type = KCST_UnconditionalGoto;
GotoThen.LHS = *CondTerm;
Context.GotoFixupRequestMap.Add(&GotoThen, ThenPin);

五、分支节点相关源码

源码文件:
K2Node_IfThenElse.h
K2Node_IfThenElse.cpp
相关类:
KCHandler_Branch
UK2Node_IfThenElse


class FKCHandler_Branch : public FNodeHandlingFunctor
{
public:
	FKCHandler_Branch(FKismetCompilerContext& InCompilerContext)
		: FNodeHandlingFunctor(InCompilerContext)
	{
	}

	virtual void Compile(FKismetFunctionContext& Context, UEdGraphNode* Node) override
	{
		// For imperative nodes, make sure the exec function was actually triggered and not just included due to an output data dependency
		FEdGraphPinType ExpectedExecPinType;
		ExpectedExecPinType.PinCategory = UEdGraphSchema_K2::PC_Exec;

		FEdGraphPinType ExpectedBoolPinType;
		ExpectedBoolPinType.PinCategory = UEdGraphSchema_K2::PC_Boolean;


		UEdGraphPin* ExecTriggeringPin = Context.FindRequiredPinByName(Node, UEdGraphSchema_K2::PN_Execute, EGPD_Input);
		if ((ExecTriggeringPin == NULL) || !Context.ValidatePinType(ExecTriggeringPin, ExpectedExecPinType))
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("NoValidExecutionPinForBranch_Error", "@@ must have a valid execution pin @@").ToString(), Node, ExecTriggeringPin);
			return;
		}
		else if (ExecTriggeringPin->LinkedTo.Num() == 0)
		{
			CompilerContext.MessageLog.Warning(*LOCTEXT("NodeNeverExecuted_Warning", "@@ will never be executed").ToString(), Node);
			return;
		}

		// Generate the output impulse from this node
		UEdGraphPin* CondPin = Context.FindRequiredPinByName(Node, UEdGraphSchema_K2::PN_Condition, EGPD_Input);
		UEdGraphPin* ThenPin = Context.FindRequiredPinByName(Node, UEdGraphSchema_K2::PN_Then, EGPD_Output);
		UEdGraphPin* ElsePin = Context.FindRequiredPinByName(Node, UEdGraphSchema_K2::PN_Else, EGPD_Output);
		if (Context.ValidatePinType(ThenPin, ExpectedExecPinType) &&
			Context.ValidatePinType(ElsePin, ExpectedExecPinType) &&
			Context.ValidatePinType(CondPin, ExpectedBoolPinType))
		{
			UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(CondPin);
			FBPTerminal** CondTerm = Context.NetMap.Find(PinToTry);

			if (CondTerm != NULL) //
			{
				// First skip the if, if the term is false
				{
					FBlueprintCompiledStatement& SkipIfGoto = Context.AppendStatementForNode(Node);
					SkipIfGoto.Type = KCST_GotoIfNot;
					SkipIfGoto.LHS = *CondTerm;
					Context.GotoFixupRequestMap.Add(&SkipIfGoto, ElsePin);
				}

				// Now go to the If branch
				{
					FBlueprintCompiledStatement& GotoThen = Context.AppendStatementForNode(Node);
					GotoThen.Type = KCST_UnconditionalGoto;
					GotoThen.LHS = *CondTerm;
					Context.GotoFixupRequestMap.Add(&GotoThen, ThenPin);
				}
			}
			else
			{
				CompilerContext.MessageLog.Error(*LOCTEXT("ResolveTermPassed_Error", "Failed to resolve term passed into @@").ToString(), CondPin);
			}
		}
	}
};

UK2Node_IfThenElse::UK2Node_IfThenElse(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
}

void UK2Node_IfThenElse::AllocateDefaultPins()
{
	const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>();

	CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
	UEdGraphPin* ConditionPin = CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Boolean, UEdGraphSchema_K2::PN_Condition);
	K2Schema->SetPinAutogeneratedDefaultValue(ConditionPin, TEXT("true"));

	UEdGraphPin* TruePin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Then);
	TruePin->PinFriendlyName =LOCTEXT("true", "true");

	UEdGraphPin* FalsePin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Else);
	FalsePin->PinFriendlyName = LOCTEXT("false", "false");

	Super::AllocateDefaultPins();
}

FText UK2Node_IfThenElse::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
	return LOCTEXT("Branch", "Branch");
}

FLinearColor UK2Node_IfThenElse::GetNodeTitleColor() const
{
	return GetDefault<UGraphEditorSettings>()->ExecBranchNodeTitleColor;
}

FSlateIcon UK2Node_IfThenElse::GetIconAndTint(FLinearColor& OutColor) const
{
	static FSlateIcon Icon("EditorStyle", "GraphEditor.Branch_16x");
	return Icon;
}

FText UK2Node_IfThenElse::GetTooltipText() const
{
	return LOCTEXT("BrancStatement_Tooltip", "Branch Statement\nIf Condition is true, execution goes to True, otherwise it goes to False");
}

UEdGraphPin* UK2Node_IfThenElse::GetThenPin() const
{
	UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Then);
	check(Pin);
	return Pin;
}

UEdGraphPin* UK2Node_IfThenElse::GetElsePin() const
{
	UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Else);
	check(Pin);
	return Pin;
}

UEdGraphPin* UK2Node_IfThenElse::GetConditionPin() const
{
	UEdGraphPin* Pin = FindPin(UEdGraphSchema_K2::PN_Condition);
	check(Pin);
	return Pin;
}

FNodeHandlingFunctor* UK2Node_IfThenElse::CreateNodeHandler(FKismetCompilerContext& CompilerContext) const
{
	return new FKCHandler_Branch(CompilerContext);
}

void UK2Node_IfThenElse::GetMenuActions(FBlueprintActionDatabaseRegistrar& ActionRegistrar) const
{
	// actions get registered under specific object-keys; the idea is that 
	// actions might have to be updated (or deleted) if their object-key is  
	// mutated (or removed)... here we use the node's class (so if the node 
	// type disappears, then the action should go with it)
	UClass* ActionKey = GetClass();
	// to keep from needlessly instantiating a UBlueprintNodeSpawner, first   
	// check to make sure that the registrar is looking for actions of this type
	// (could be regenerating actions for a specific asset, and therefore the 
	// registrar would only accept actions corresponding to that asset)
	if (ActionRegistrar.IsOpenForRegistration(ActionKey))
	{
		UBlueprintNodeSpawner* NodeSpawner = UBlueprintNodeSpawner::Create(GetClass());
		check(NodeSpawner != nullptr);

		ActionRegistrar.AddBlueprintAction(ActionKey, NodeSpawner);
	}
}

FText UK2Node_IfThenElse::GetMenuCategory() const
{
	return FEditorCategoryUtils::GetCommonCategory(FCommonEditorCategory::FlowControl);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1458347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode1049:最后一块石头的重量二

解题思路&#xff1a; 把石头堆分割成差不多的两堆&#xff0c;使得两堆差值最小 dp数组的含义&#xff1a; dp[j]:背包容量为j的背包最大重量(价值)为dp[j] dp[j] max(dp[j],dp[j-stones[i]] stones[i]) 初始化&#xff1a;&#xff08;dp数组的大小根据题目进行定义&a…

华为配置旁挂二层组网隧道转发示例

配置旁挂二层组网隧道转发示例 组网图形 业务需求组网需求数据规划配置思路配置注意事项操作步骤配置文件扩展阅读 业务需求 企业用户通过WLAN接入网络&#xff0c;以满足移动办公的最基本需求。且在覆盖区域内移动发生漫游时&#xff0c;不影响用户的业务使用。 组网需求 AC组…

【总结】linux命令行在个人用户下添加环境变量

一&#xff0c;简介 在工作过程中需要将对应的路径添加到个人用户的环境变量中&#xff0c;本文介绍如何添加&#xff0c;供参考。 二&#xff0c;操作步骤 非常简单&#xff0c;只需要找到对应配置文件&#xff0c;将路径添加进去即可。 2.1 找到配置文件 一般为用户名下…

【无标题】力扣报错:member access within null pointer of type ‘struct ListNode‘

项目场景&#xff1a; 做单链表反转题目&#xff0c;报错&#xff1a;member access within null pointer of type ‘struct ListNode’ 题目链接:LINK 问题描述 我明明在初始化指针时候&#xff0c;已经处理了n2->next情况却依然报错 这个报错提示含义是&#xff1a;大概就…

react封装通用Modal弹窗组件

目录 1、【src/component/modal/hoc.js】 2、【src/component/modal/componentModal.js】 3、【src/page/projectView.js】 【说明】&#xff1a;后台管理的项目中会经常遇到弹窗&#xff0c;于是封装了一个简单的公共弹窗组件 这个公共组件不适用复杂的功能&#xff0c;简单的…

力扣题目训练(17)

2024年2月10日力扣题目训练 2024年2月10日力扣题目训练551. 学生出勤记录 I557. 反转字符串中的单词 III559. N 叉树的最大深度241. 为运算表达式设计优先级260. 只出现一次的数字 III126. 单词接龙 II 2024年2月10日力扣题目训练 2024年2月10日第十七天编程训练&#xff0c;今…

第五次作业(防御安全)

需求: 1.办公区设备可以通过电信链路和移动链路上网&#xff08;多对多的NAT&#xff0c;并且需要保留一个公网IP 不能用来转换&#xff09; 2.分公司设备可以通过总公司的移动链路和电信链路访问到DMZ区的http服务器 3.分公司内部的客户端可以通过公网地址访问到内部的服务…

力扣OJ题——相交链表

题目&#xff1a;160. 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 思路一&#xff08;暴力求解&#xff09;&#xff1a; A链表的每个节点依次跟B链表中节点进行…

xshell 修改时间破解使用

文章目录 xshell 修改时间破解使用:question: 问题:point_right: 解决方案&#xff1a; xshell 修改时间破解使用 参考地址&#xff1a;博客地址 ❓ 问题 问题 ​ 当前 xshell 官方提供免费的个人版本供使用&#xff0c;但是在官网升级新版本后则需要进行升级之后才能使用&…

调用接口时不时出现 Error: socket hang up

项目场景&#xff1a; 提示&#xff1a;这里简述项目相关背景&#xff1a; 今天采用golang创建了一个http服务&#xff0c;准备对若干接口进行测试。 问题描述 提示&#xff1a;这里描述项目中遇到的问题&#xff1a; 在测试第一个接口时&#xff0c;发现采用postman调用接口…

Fisher-Yates乱序算法

乱序算法 public class Test07 {public static void main(String[] args) {//乱序算法int[] arr {1,2,3,4,5,6,7,8};//逆序遍历 且这个随机的下标不能使要交换的元素的本身for(int i arr.length-1;i>0;i--){//产生一个随机的下标与当前元素进行交换int index (int)(Math…

文件包含+文件上传漏洞(图片马绕过)

目录 一.文件包含二.文件上传三.图片马四.题目 一.文件包含 将已有的代码以文件形式包含到某个指定的代码中&#xff0c;从而使用其中的代码或者数据&#xff0c;一般是为了方便直接调用所需文件&#xff0c;文件包含的存在使得开发变得更加灵活和方便&#xff08;若对用户输入…

【无刷电机学习】基础概念及原理入门介绍

目录 0 参考出处 1 定义 2 各种电机优势比较 2.1 有刷与无刷比较 2.2 交流与直流比较 2.3 内转子与外转子比较 2.4 低压BLDC的一些优点 3 基本原理 3.1 单相无刷电机 3.2 三相无刷电机 4 驱动方法 4.1 六步换相控制 4.2 正弦波控制 5 转子位置信息的获取 5…

安卓游戏开发之图形渲染技术优劣分析

一、引言 随着移动设备的普及和性能的提升&#xff0c;安卓游戏开发已经成为一个热门领域。在安卓游戏开发中&#xff0c;图形渲染技术是关键的一环。本文将对安卓游戏开发中常用的图形渲染技术进行分析&#xff0c;比较它们的优劣&#xff0c;并探讨它们在不同应用场景下的适用…

辽宁博学优晨教育:引领视频剪辑新风尚,打造教育界的剪辑大师

在数字化时代&#xff0c;视频剪辑已经成为一项不可或缺的技能。辽宁博学优晨教育凭借其卓越的教学质量和实践经验&#xff0c;成功开启了视频剪辑培训的新篇章&#xff0c;为广大学习者提供了一个可靠的学习平台。今天&#xff0c;就让我们一起走进博学优晨教育&#xff0c;探…

Python打发无聊时光:5.用PyQt实现简陋的用户交互界面

第一步:安装PyQt5库 在终端输入: pip install pyqt5 第二步:复制下列代码 import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton from PyQt5.QtCore import Qt from PyQt5.QtGui import QFontclass I…

Electron实战之菜单与托盘

菜单、托盘是桌面端应用必备的功能之一&#xff0c;我们通常会在菜单上配置应用常用的&#xff1a;偏好设置、显示隐藏、打开文件等功能&#xff0c;在托盘内设置&#xff1a;退出、重启、帮助等辅助性功能&#xff0c;帮助用户方便快捷地控制应用的一些系统功能。系统托盘实际…

c#,dotnet, DataMatrix 类型二维码深度识别,OCR,(基于 Halcon)

代码中部分调用的 c 函数参数&#xff0c;具体说明自行研究~&#xff08;我也是参考的其他资源&#xff0c;还没研究透彻&#xff09; 例如&#xff1a;HOperatorSet.GenRectangle2() &#xff0c; 2000, 2000, 0, 2000, 2000 这些数字应该是选取的图片解析范围、尺寸&#xff…

Programming Abstractions in C阅读笔记:p283-p292

《Programming Abstractions in C》学习第72天&#xff0c;p283-p292总结&#xff0c;总计10页。 一、技术总结 1、anylasis of algorithms 算法分析——即判断程序的效率(efficiency)。 2、mathematical induction(数学归纳法) 3、Big-O notation(大O标记法) 4、constan…

Linux系统——http协议介绍

目录 引言——Internet起源 一、http协议——超文本传输协议 1.http相关概念 2.访问浏览器的过程 3.http协议通信过程 4.http相关技术 4.1WEB开发语言 4.2html 4.3CSS 4.4JS 5.MIME——Multipurpose Internet Mail Extensions 多用途互联网邮件扩展 6.URI URN URL的…