UE蓝图 Cast节点和源码

系列文章目录

UE蓝图 Cast节点和源码


文章目录

  • 系列文章目录
  • Cast节点功能
  • 一、Cast节点用法
  • 二、Cast节点使用场景
  • 三、Cast节点实现步骤
  • 四、Cast节点源码


Cast节点功能

在Unreal Engine(UE)中,Cast节点是一种蓝图系统中的节点,用于执行类型转换操作。Cast节点用于检测一个对象是否可以被转换(或“投射”)为另一种类型,并在转换成功时返回转换后的对象。

在这里插入图片描述
具体来说,当你在蓝图中使用Cast节点时,你正在尝试将一个对象转换(或投射)为另一种类型。例如,如果你有一个“玩家角色”对象,并且你想检查它是否是一个特定的“MyCharacter”类型的实例,你可以使用“Get Player Character”节点来获取玩家角色,然后使用“Cast To MyCharacter”节点来尝试将其转换为“MyCharacter”类型。如果转换成功,你就可以访问该对象的特定变量、函数和事件。
上图对应的代码如下:

 bpfv__CallFunc_GetParentActor_ReturnValue__pf = AActor::GetParentActor();
 bpfv__K2Node_DynamicCast_As____pf = Cast<ACharacter>(bpfv__CallFunc_GetParentActor_ReturnValue__pf);
 bpfv__K2Node_DynamicCast_bSuccess__pf = (bpfv__K2Node_DynamicCast_As____pf != nullptr);;
 if (!bpfv__K2Node_DynamicCast_bSuccess__pf)
 {
     __CurrentState = -1;
	 break;
 }

一、Cast节点用法

当然可以。UE Cast节点在Unreal Engine的蓝图系统中的具体用法主要涉及以下步骤:

  1. 获取对象引用:首先,你需要有一个对象引用,这通常是通过其他蓝图节点获取的。例如,你可能有一个指向某个游戏对象(如玩家角色、敌人等)的引用。

  2. 添加Cast节点:在蓝图中,你需要添加一个Cast节点。这个节点通常位于“类型转换”类别下。添加后,你将看到两个主要的输出端:一个是转换后的对象引用,另一个是表示转换是否成功的布尔值(bool)。

  3. 配置Cast节点:在Cast节点的属性窗口中,你需要指定目标类型,即你希望将对象转换成的类型。这通常是一个类名,比如MyCharacterMyComponent

  4. 连接对象引用:将你想要转换的对象引用连接到Cast节点的输入端。这通常是通过从获取对象引用的节点拖一条线到Cast节点的输入端来完成的。

  5. 使用转换后的对象:Cast节点有两个输出端。第一个输出端输出转换后的对象引用。如果转换成功,这个输出端将是非空的(即有效的)。你可以将这个输出端连接到需要该类型对象的任何节点上。

  6. 检查转换是否成功:Cast节点的第二个输出端是一个布尔值,表示转换是否成功。你可以将这个输出端连接到条件逻辑节点(如Branch节点)上,以便在转换成功时执行一段逻辑,在转换失败时执行另一段逻辑。

  7. 处理转换失败的情况:如果转换失败(即对象不能被转换为目标类型),你可能需要执行一些备选逻辑。这可以通过使用Cast节点的第二个输出端(布尔值)来实现,将其连接到一个条件节点,以便在转换失败时执行特定的操作。

二、Cast节点使用场景

UE Cast节点在蓝图系统中有多种应用场景,这些场景主要涉及到需要动态类型转换或检查的地方。以下是一些常见的UE Cast节点应用场景:

  1. 继承与多态处理:在面向对象编程中,Cast节点常用于处理继承关系。例如,当你有一个基类指针或引用,并且你想调用仅在派生类中定义的函数时,你需要先使用Cast节点将其转换为派生类类型。

  2. 接口实现检查:如果一个对象实现了某个接口,你可以使用Cast节点来检查这个对象是否确实实现了该接口,并据此执行相应的操作。

  3. 组件查询与访问:在UE中,组件通常附加到实体(如Actor)上。你可以使用Cast节点来尝试将实体转换为特定的组件类型,以便直接访问该组件的属性和方法。

  4. 动态类型识别:在某些情况下,你可能不知道对象的确切类型,但需要根据其类型执行不同的逻辑。通过使用Cast节点,你可以尝试将对象转换为多种可能的类型,并根据转换是否成功来决定执行哪段逻辑。

  5. 事件处理:在处理事件或委托时,你可能会接收到一个通用类型的参数。使用Cast节点,你可以将这个通用参数转换为更具体的类型,以便在事件处理逻辑中使用。

  6. 资源加载与转换:在加载资源时,资源可能以通用或基类形式被加载。在使用资源之前,你可能需要将其转换为正确的派生类型。

  7. 错误处理与调试:在开发过程中,Cast节点可以帮助你验证对象是否如你所期望的那样被正确创建和管理。如果Cast失败,这可能表明存在编程错误或资源管理问题。

三、Cast节点实现步骤

  • 创建输入输出引脚
		// Input - Execution Pin
		CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);
		// Output - Execution Pins
		CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_CastSucceeded);
		CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_CastFailed);
		// Input - Source type Pin
	CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, UObject::StaticClass(), UEdGraphSchema_K2::PN_ObjectToCast);
	CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, *TargetType, *CastResultPinName);
	UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Boolean, UK2Node_DynamicCastImpl::CastSuccessPinName);
  • 注册Net
	FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net));
	Context.NetMap.Add(Net, Term);
  • 编译
    创建转换Statement
	// Cast Statement
	FBlueprintCompiledStatement& CastStatement = Context.AppendStatementForNode(Node);
	CastStatement.Type = CastOpType;
	CastStatement.LHS = *CastResultTerm;
	CastStatement.RHS.Add(ClassTerm);
	CastStatement.RHS.Add(*ObjectToCast);

四、Cast节点源码


void UK2Node_DynamicCast::AllocateDefaultPins()
{
	const bool bReferenceObsoleteClass = TargetType && TargetType->HasAnyClassFlags(CLASS_NewerVersionExists);
	if (bReferenceObsoleteClass)
	{
		Message_Error(FString::Printf(TEXT("Node '%s' references obsolete class '%s'"), *GetPathName(), *TargetType->GetPathName()));
	}
	ensure(!bReferenceObsoleteClass);

	const UEdGraphSchema_K2* K2Schema = Cast<UEdGraphSchema_K2>(GetSchema());
	check(K2Schema != nullptr);
	if (!K2Schema->DoesGraphSupportImpureFunctions(GetGraph()))
	{
		bIsPureCast = true;
	}

	if (!bIsPureCast)
	{
		// Input - Execution Pin
		CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_Execute);

		// Output - Execution Pins
		CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_CastSucceeded);
		CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Exec, UEdGraphSchema_K2::PN_CastFailed);
	}

	// Input - Source type Pin
	CreatePin(EGPD_Input, UEdGraphSchema_K2::PC_Wildcard, UObject::StaticClass(), UEdGraphSchema_K2::PN_ObjectToCast);

	// Output - Data Pin
	if (TargetType)
	{
		const FString CastResultPinName = UEdGraphSchema_K2::PN_CastedValuePrefix + TargetType->GetDisplayNameText().ToString();
		if (TargetType->IsChildOf(UInterface::StaticClass()))
		{
			CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Interface, *TargetType, *CastResultPinName);
		}
		else 
		{
			CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Object, *TargetType, *CastResultPinName);
		}
	}

	UEdGraphPin* BoolSuccessPin = CreatePin(EGPD_Output, UEdGraphSchema_K2::PC_Boolean, UK2Node_DynamicCastImpl::CastSuccessPinName);
	BoolSuccessPin->bHidden = !bIsPureCast;

	Super::AllocateDefaultPins();
}

void FKCHandler_DynamicCast::RegisterNets(FKismetFunctionContext& Context, UEdGraphNode* Node)
{
	FNodeHandlingFunctor::RegisterNets(Context, Node);

	if (const UK2Node_DynamicCast* DynamicCastNode = Cast<UK2Node_DynamicCast>(Node))
	{
		UEdGraphPin* BoolSuccessPin = DynamicCastNode->GetBoolSuccessPin();
		// this is to support backwards compatibility (when a cast node is generating code, but has yet to be reconstructed)
		// @TODO: remove this at some point, when backwards compatibility isn't a concern
		if (BoolSuccessPin == nullptr)
		{
			// Create a term to determine if the cast was successful or not
			FBPTerminal* BoolTerm = Context.CreateLocalTerminal();
			BoolTerm->Type.PinCategory = UEdGraphSchema_K2::PC_Boolean;
			BoolTerm->Source = Node;
			BoolTerm->Name = Context.NetNameMap->MakeValidName(Node, TEXT("CastSuccess"));
			BoolTermMap.Add(Node, BoolTerm);
		}
	}
	
}

void FKCHandler_DynamicCast::RegisterNet(FKismetFunctionContext& Context, UEdGraphPin* Net)
{
	FBPTerminal* Term = Context.CreateLocalTerminalFromPinAutoChooseScope(Net, Context.NetNameMap->MakeValidName(Net));
	Context.NetMap.Add(Net, Term);
}

void FKCHandler_DynamicCast::Compile(FKismetFunctionContext& Context, UEdGraphNode* Node)
{
	const UK2Node_DynamicCast* DynamicCastNode = CastChecked<UK2Node_DynamicCast>(Node);

	if (DynamicCastNode->TargetType == NULL)
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("BadCastNoTargetType_Error", "Node @@ has an invalid target type, please delete and recreate it").ToString(), Node);
	}

	// Self Pin
	UEdGraphPin* SourceObjectPin = DynamicCastNode->GetCastSourcePin();
	UEdGraphPin* PinToTry = FEdGraphUtilities::GetNetFromPin(SourceObjectPin);
	FBPTerminal** ObjectToCast = Context.NetMap.Find(PinToTry);

	if (!ObjectToCast)
	{
		ObjectToCast = Context.LiteralHackMap.Find(PinToTry);

		if (!ObjectToCast || !(*ObjectToCast))
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidConnectionOnNode_Error", "Node @@ has an invalid connection on @@").ToString(), Node, SourceObjectPin);
			return;
		}
	}

	// Output pin
	const UEdGraphPin* CastOutputPin = DynamicCastNode->GetCastResultPin();
	if( !CastOutputPin )
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("InvalidDynamicCastClass_Error", "Node @@ has an invalid target class").ToString(), Node);
		return;
	}

	FBPTerminal** CastResultTerm = Context.NetMap.Find(CastOutputPin);
	if (!CastResultTerm || !(*CastResultTerm))
	{
		CompilerContext.MessageLog.Error(*LOCTEXT("InvalidDynamicCastClass_CompilerError", "Node @@ has an invalid target class. (Inner compiler error?)").ToString(), Node);
		return;
	}

	// Create a literal term from the class specified in the node
	FBPTerminal* ClassTerm = Context.CreateLocalTerminal(ETerminalSpecification::TS_Literal);
	ClassTerm->Name = DynamicCastNode->TargetType->GetName();
	ClassTerm->bIsLiteral = true;
	ClassTerm->Source = Node;
	ClassTerm->ObjectLiteral = DynamicCastNode->TargetType;
	ClassTerm->Type.PinCategory = UEdGraphSchema_K2::PC_Class;

	UClass const* const InputObjClass  = Cast<UClass>((*ObjectToCast)->Type.PinSubCategoryObject.Get());
	UClass const* const OutputObjClass = Cast<UClass>((*CastResultTerm)->Type.PinSubCategoryObject.Get());

	const bool bIsOutputInterface = ((OutputObjClass != NULL) && OutputObjClass->HasAnyClassFlags(CLASS_Interface));
	const bool bIsInputInterface  = ((InputObjClass != NULL) && InputObjClass->HasAnyClassFlags(CLASS_Interface));

	EKismetCompiledStatementType CastOpType = KCST_DynamicCast;
	if (bIsInputInterface)
	{
		if (bIsOutputInterface)
		{
			CastOpType = KCST_CrossInterfaceCast;
		}
		else
		{
			CastOpType = KCST_CastInterfaceToObj;
		}
	}
	else if (bIsOutputInterface)
	{
		CastOpType = KCST_CastObjToInterface;
	}

	if (KCST_MetaCast == CastType)
	{
		if (bIsInputInterface || bIsOutputInterface)
		{
			CompilerContext.MessageLog.Error(*LOCTEXT("InvalidClassDynamicCastClass_Error", "Node @@ has an invalid target class. Interfaces are not supported.").ToString(), Node);
			return;
		}
		CastOpType = KCST_MetaCast;
	}

	// Cast Statement
	FBlueprintCompiledStatement& CastStatement = Context.AppendStatementForNode(Node);
	CastStatement.Type = CastOpType;
	CastStatement.LHS = *CastResultTerm;
	CastStatement.RHS.Add(ClassTerm);
	CastStatement.RHS.Add(*ObjectToCast);

	FBPTerminal** BoolSuccessTerm = nullptr;
	if (UEdGraphPin* BoolSuccessPin = DynamicCastNode->GetBoolSuccessPin())
	{
		BoolSuccessTerm = Context.NetMap.Find(BoolSuccessPin);
	}
	else
	{
		BoolSuccessTerm = BoolTermMap.Find(DynamicCastNode);
	}	
	check(BoolSuccessTerm != nullptr);

	// Check result of cast statement
	FBlueprintCompiledStatement& CheckResultStatement = Context.AppendStatementForNode(Node);
	CheckResultStatement.Type = KCST_ObjectToBool;
	CheckResultStatement.LHS  = *BoolSuccessTerm;
	CheckResultStatement.RHS.Add(*CastResultTerm);

	UEdGraphPin* SuccessExecPin = DynamicCastNode->GetValidCastPin();
	bool const bIsPureCast = (SuccessExecPin == nullptr);
	if (!bIsPureCast)
	{
		UEdGraphPin* FailurePin = DynamicCastNode->GetInvalidCastPin();
		check(FailurePin != nullptr);
		// Failure condition...skip to the failed output
		FBlueprintCompiledStatement& FailCastGoto = Context.AppendStatementForNode(Node);
		FailCastGoto.Type = KCST_GotoIfNot;
		FailCastGoto.LHS  = *BoolSuccessTerm;
		Context.GotoFixupRequestMap.Add(&FailCastGoto, FailurePin);

		// Successful cast...hit the success output node
		FBlueprintCompiledStatement& SuccessCastGoto = Context.AppendStatementForNode(Node);
		SuccessCastGoto.Type = KCST_UnconditionalGoto;
		SuccessCastGoto.LHS  = *BoolSuccessTerm;
		Context.GotoFixupRequestMap.Add(&SuccessCastGoto, SuccessExecPin);
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何高效利用FMEA,FMEA实施流程有哪些——SunFMEA软件系统

FMEA作为是一种预防性的质量工具&#xff0c;用于识别、评估和解决潜在的设计和过程故障模式。通过FMEA的实施&#xff0c;可以在产品或过程的开发阶段发现并解决潜在问题&#xff0c;从而减少产品或过程的故障风险。如何高效利用FMEA呢&#xff0c;接下来SunFMEA软件和大家一起…

kali虚拟机桥接模式快速设置

第一步&#xff1a;配置 IP、掩码、网关 vim /etc/network/interfaces第二步&#xff1a;配置 DNS&#xff1a; vi /etc/resolv.conf第三步&#xff1a;重启网卡 service networking restart如果还不行建议重启一下虚拟机

CCF-A类MobiCom历年高引论文集免费放送!

MobiCom 高引论文集 MobiCom(International Conference On Mobile Computing And Networking )会议是无线网络和移动计算领域的重要盛会&#xff0c;对推动该领域发展起着积极的推动作用&#xff01;贴心的会议之眼已经免费为大家带来30篇高质量的MobiCom被广泛引用论文&#x…

Sora 和之前 Runway 在架构上的区别

问&#xff1a;Sora 和之前 Runway 那些在架构上有啥区别呢&#xff1f; 答&#xff1a;简单来说 Runway 是基于扩散模型&#xff08;Diffusion Model&#xff09;的&#xff0c;而 Sora 是基于 Diffusion Transformer。 Runway、Stable Diffusion 是基于扩散模型&#xff08…

JavaScript中延迟加载的方式有哪些

在web前端开发中&#xff0c;性能优化一直是一个非常重要的话题。当我们开发一个页面时&#xff0c;为了提高用户的体验和页面加载速度&#xff0c;我们往往需要采用一些延迟加载的技术。JavaScript中延迟加载的方式有很多种&#xff0c;下面我将为大家详细介绍几种常用的方式。…

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…

Python Flask Web + PyQt 前后端分离的项目—学习成绩可视化分析系统

简介 使用工具&#xff1a; Python&#xff0c;PyQt &#xff0c;Flask &#xff0c;MySQL 注&#xff1a;制作重点在网页端&#xff0c;因此网页端的功能更全 WEB界面展示: 系统登录分为管理员&#xff0c;老师&#xff0c;学生3部分 管理员统一管理所有的账号信息以及登录…

Java实现一个栈

目录 概念与结构 实现一个栈 创建一个栈类 实现栈的基本操作 测试栈类 概念与结构 概念与结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元…

算法练习-分割等和子集(思路+流程图+代码)

难度参考 难度&#xff1a;困难 分类&#xff1a;动态规划 难度与分类由我所参与的培训课程提供&#xff0c;但需 要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0…

[AIGC] 深入理解 Java 虚拟机(JVM)的垃圾回收

深入理解 Java 虚拟机&#xff08;JVM&#xff09;的垃圾回收 一、是什么 Java 虚拟机&#xff08;JVM&#xff09;的垃圾回收&#xff08;Garbage Collection&#xff09;是一种自动内存管理机制&#xff0c;用于释放不再使用的对象所占用的内存空间。垃圾回收的目标是回收那…

【HTML】SVG实现炫酷的描边动画

前沿 今天闲来无事&#xff0c;看到Antfu大佬的个性签名&#xff0c;觉得还是非常炫酷的&#xff0c;于是也想要搞一个自己的个性签名用来装饰自己的门面&#xff0c;不过由于手写的签名太丑了&#xff0c;遂放弃。于是尝试理解原理&#xff0c;深入研究此等密法&#xff0c;终…

如何录制视频?让你的录制过程更加顺畅!

录制视频是现代社会不可或缺的技能之一&#xff0c;无论是工作还是生活&#xff0c;我们都需要学会如何录制和编辑视频&#xff0c;可是您知道如何录制视频吗&#xff1f;本文将介绍两种录制视频的方法&#xff0c;这两种方法各有特点&#xff0c;可以满足不同用户的需求。 如何…

Windows制作Ubuntu的U盘启动盘

概要&#xff1a; 本篇演示在Windows10中制作Ubuntu22.04的U盘启动盘 一、下载Ubuntu22.04的iso文件 在浏览器中输入https://ubuntu.com去Ubuntu官网下载Ubuntu22.04的iso文件 二、下载Ultraiso 在浏览器中输入https://www.ultraiso.com进入ultraiso官网 点击FREE TRIAL&a…

腾讯云4核8G12M服务器支持多少人在线?

4核8G服务器支持多少人同时在线访问&#xff1f;阿腾云的4核8G服务器可以支持20个访客同时访问&#xff0c;关于4核8G服务器承载量并发数qps计算测评&#xff0c;云服务器上运行程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&…

最高频率的图形工作站应用配置推荐

如果你的计算机速度太慢&#xff0c;想买一台最快的图形工作站&#xff0c;大幅提高你的工作效率&#xff0c;从专业角度&#xff0c;这种图形工作站不是唯一的&#xff0c;原因是&#xff0c;不同的应用、不同的算法、不同计算规模&#xff0c;硬件配置有很大差异&#xff0c;…

书生开源大模型-第2讲-笔记

1.环境准备 1.1环境 先克隆我们的环境 bash /root/share/install_conda_env_internlm_base.sh internlm-demo1.2 模型参数 下载或者复制下来&#xff0c;开发机中已经有一份参数了 mkdir -p /root/model/Shanghai_AI_Laboratory cp -r /root/share/temp/model_repos/inter…

大数据信用风险检测,多久查一次比较好?

自从大数据技术的出现&#xff0c;就被广泛的运用到金融风控行业&#xff0c;逐渐成为不少银行和机构进行贷前风险排查的重要工具&#xff0c;大数据信用的重要性也日益的显现出来&#xff0c;那大数据信用风险检测&#xff0c;多久查一次比较好呢?本文为你详细讲讲。 大数据信…

[AudioRecorder]iPhone苹果通话录音汉化破解版-使用巨魔安装-ios17绕道目前还不支持

首先你必须有巨魔才能使用&#xff01;&#xff01; 不会安装的&#xff0c;还没安装的移步这里&#xff0c;ios17 以上目前装不了&#xff0c;别看了&#xff1a;永久签名 | 网址分类目录 | 路灯iOS导航-苹果签名实用知识网址导航-各种iOS技巧-后厂村路灯 视频教程 【Audio…

森林消防利器:智能高压森林应急消防泵

在森林火灾防控工作中&#xff0c;智能高压森林应急消防泵发挥着至关重要的作用。它是一种由高强度耐腐蚀材料加工制造而成的消防泵&#xff0c;具有体积小、重量轻、压力大、扬程高、流量大、输水距离远等优点&#xff0c;运行可靠&#xff0c;能够迅速扑灭森林火灾&#xff0…

SG-9101CB(可编程+105℃晶体振荡器)

SG-9101CB 系列是一款高精度可编程性的晶体振荡器&#xff0c;能够在0.67 MHz至170 MHz的频率范围内以1ppm的步长精确调整频率。这款振荡器支持宽范围的电源电压&#xff08;1.62 V至3.63V&#xff09;&#xff0c;并提供使能&#xff08;OE&#xff09;或待机&#xff08;ST&a…