UE4蓝图解析(一)
简介
蓝图是一类特殊的asset,可以使用直观、基于节点的方式创建逻辑,或者设置一些变量数据。策划可以创建自定义的Actor、Event、函数等等,快速的做Gameplay迭代,不需要写任何代码。
蓝图也可以选择继承C 类,获取C 中定义的变量,调用C 中定义的函数,或者实现C 中定义的event。
以下是一个使用节点创建控制流程的例子:
整个逻辑看起来非常直关,而且蓝图运行在专门的蓝图虚拟机中,对蓝图做出修改后不需要像C 一样重新编译,只要重新生成一下蓝图字节码,就可立即运行。
关于蓝图的详细介绍可见官方文档:https://api.unrealengine.com/CHN/Engine/Blueprints/index.html
内容规划
UE4的蓝图系统相当庞大,因此本文章会聚焦蓝图的底层实现,以及蓝图可视化编程原理。关于蓝图的文章总共分为四个部分。
第一部分主要介绍蓝图相关的类结构
第二部分介绍蓝图虚拟机,以及蓝图和C 函数的相互调用
第三部分介绍如何从可视化的节点生成中间编译单元:Statement
第四部分介绍Statement优化和字节码生成
Blueprint类实现
一个蓝图在内存中通常由UBlueprint类进行描述,蓝图有关类的继承关系如下:
BlueprintCore:
作为蓝图的基类,继承自UObject,其中内容并不多。
主要成员变量:
TSubclassOf SkeletonGeneratedClass:指向skeleton class的指针,每当向蓝图中添加一个变量或者函数时,都会重新生成skeleton class。但是skeleton class只是一个框架类,比如它不包含字节码和自动生成的内部变量。在编译蓝图时,可以设置CompileType为SkeletonOnly来只生成skeleton class。
TSubclassOf GeneratedClass:指向全编译class的指针,通常使用的都是这个class,其内部的属性都被填充,可以完整的描述一个蓝图。由于蓝图类class是就地编译的,因此不管编译几次,这个指针都不需要改变。
FGuid BlueprintGuid:蓝图的Guid,根据蓝图的资源路径hash生成。
UBlueprint:
负责实现蓝图的主要功能,包括蓝图属性、蓝图函数、节点连接关系等。
主要成员变量:
TSubclassOf ParentClass:指向蓝图类父类的UClass。会注册到AssetRegistryTags中,以支持蓝图预览。
TArray UbergraphPages:所有ubergraphpages,一个ubergraph就是编辑器左侧显示的一个eventgraph,里面会包含所有event的实现,在蓝图编译时,它们会被复制到一个大的ubergraph中。
TArray FunctionGraphs:所有函数graph,ConstructionScript也是一个函数。
TArray DelegateSignatureGraphs:所有事件代理Graph。
TArray MacroGraphs:所有这个蓝图实现的宏。
TArray EventGraphs:所有的Event声明。
TArray Timelines:蓝图中的Timeline,timeline需要被特别处理。
TArray NewVariables:这个蓝图自己创建的变量,不包含从父类继承的,在编译时会添加到BlueprintGeneratedClass中。
TArray Breakpoints:断点集合,用于调试
其实,蓝图编译过程就是把UBlueprint描述的信息转换为BlueprintGeneratedClass的过程。
图&节点
蓝图有很多功能,包括数据资源配置、创建UI界面等等,但最强大的功能就是可以基于节点和连线使用图形化的方式创建逻辑流程,不用写C 代码。这极大的提升了项目的迭代速度,而且能解放程序员生产力。而蓝图的图形化变成功能主要就是由“图”和“节点”这两个概念实现的。
图(UEdGraph)
UE4的图可以理解为蓝图编辑器中间的那块区域,可以在图中创建节点,并用线把各个节点连接起来,形成一个执行流。比如下图:
图的基类是UEdGraph,它有许多派生类,比如UAIGraph、UAnimationGraph等,用于实现不同模块的功能。图的继承关系如下:
UEdGraph:
主要成员变量:
TSubclassOf Schema:这个图要遵循的schema。
TArray Nodes:图中的所有节点。
TArray SubGraphs:这个图包含的子图,一个例子就是动画蓝图的状态机,状态机就作为子图存在。
UEdGraph可以理解为节点数据的容器。
模式(UEdGraphSchema)
模式是与Graph对应的,约定了当前Graph能创建什么样的节点、两个引脚能否产生连接等等。类的继承关系如下:
UEdGraphSchema
主要方法:
GetGraphContextActions():在当前蓝图的空白处单击右键出现的节点菜单栏,列出了当前Graph能添加的所有节点
GetContextMenuActions():在节点或引脚上右键出现的操作菜单栏,比如deletelink、break等
CanCreateConnection():传入两个引脚,判断两个引脚间能否建立连线。返回的并不是一个boo值,而是枚举ECanCreateConnectionResponse,包含了更多信息。
举个例子,CONNECT_RESPONSE_BREAK_OTHERS_A,断开引脚A上的其他连接,然后创建AB间的连接,连接两个执行引脚就是这样的。
节点(UEdGraphNode)
一个图由许多节点组成,比如上面的Graph例子图片,每个节点都有自己的功能,就像一个个砖块,节点的基类为UEdGraphNode。上面提到了多种图,因此也会有和图对应的节点。而UK2Node比较特别,因为它是所有蓝图节点的基类,这里说的蓝图节点就是普通意义上的蓝图节点,例如ifelse、方法调用、for循环等。节点的继承关系如下:
UEdGraphNode:
主要成员变量:
TArray Pins:节点上的所有引脚。
int32 NodePosX,NodePosY,NodeWidth,NodeHeight:节点的位置,长宽,在展开时会用到,避免节点间产生重叠。
可以看到,UEdGraphNode只是提供了一个基本的节点描述功能,不同类型节点的逻辑都需要由对应的子类进行约定。比如一个IfThenElse节点:
执行input节点,数据input节点,两个输出节点都由UK2Node_IfThenElse创建,数据input节点的默认值也由UK2Node_IfThenElse设置,这些都可以理解为一个节点的外在表现。
而一个节点的内在含义,或者说逻辑,由FNodeHandlingFunctor类实现。比如IfThenElse节点,Condtion为true时走then输出引脚,为false时走else输出引脚,这个逻辑就由继承FNodeHandlingFunctor的FKCHandler_Branch实现。
FNodeHandlingFunctor
是处理一类节点编译的帮助类,类图如下:
FNodeHandlingFunctor:
主要方法:
RegisterNets():用于注册引脚和创建Terminal。例如,K2Node_Self会把节点的self pin与一个Terminal对应起来,FKCHandler_Switch会创建一个中间BoolTerm用于存储输入变量与各个值的比较结果。
Compile():用于在编译时生成FBlueprintCompiledStatement,这可以理解为抽象语法树的节点,在下文中会有介绍。
RegisterLiteral():用于注册字面Terminal。
- 上一篇:UE4游戏中的大场景怎么制作?
- 下一篇:虚幻4如何做后期优化处理教程
评论列表