[程式] UE4 Blueprints In-depth - Part 2

楼主: yekdniw (yekdniw)   2019-06-22 20:50:11
网页版
https://yekdniwunrealengine.blogspot.com/2019/06/blueprints-in-depth-part-2.html
Unreal 官方公布了两个有关blueprint的深度介绍的影片
Blueprints In-depth - Part 1 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=j6mskTgL7kU
我写的Part 1说明~
https://yekdniwunrealengine.blogspot.com/2019/06/blueprints-in-depth-part-1.html
Blueprints In-depth - Part 2 | Unreal Fest Europe 2019 | Unreal Engine
https://www.youtube.com/watch?v=0YMS2wnykbc
投影片
https://epicgames.ent.box.com/s/hdv4bye3dezabp4duq8pttsha8kjjlde
这篇文章是摘录Part 2的一些重点出来~
Compliation
BP的编译时间是不会影响程式实际执行时间的。
但是对于开发者来说,如果BP编译太久会严重影响到开发过程
也有可能在使用编辑器时发生内存吃太凶的问题
BP编译时间通常跟以下几点有相关
1. BP graph内的节点数目
2. 与其他BP有reference,或是有cast其他BP。
3. BP有Circular reference。
BP大小是有上限的,不过无论如何一般的使用情境都应该远低于上限才对。
如果你不小心撞到BP的上限,代表你对BP理解是有问题的。
BP Macro如同C++的Macro概念一样,会在呼叫Macro的地方直接展开Macro的内容
也就是说呼叫Macro就跟复制贴上BP节点差不多,
使用过多复杂的Macro是会增加BP编译时间的
BP Function的行为与Macro有很大的不同,不会复制贴上,
所以如果把Macro转为Function的话,可以有效的降低BP编译时间。
将复杂的BP分为多个actor,或是多个component,或是child actor,或是以C++改写,
都能有效降低编译时间。
不过这部份就牵扯到系统设计,要选择哪一种方法完全就是要看情况而决定,
没有完美的答案。
Casting(型别转换)
除了BP节点数之外,Cast对于编译时间的影响是很大的。
假设BP_a内有cast到BP_b的节点,那么在打开BP_a的时候,
会先编译BP_b后才会开始编译BP_a。
所以一个cast可能就会牵连出冗长复杂的关系,在使用cast的时候务必要注意。
要注意的是即使是拿cast的InValid作条件检查,也一样会产生reference,
即使你没有拿cast完的object来使用。
笔者:其实你放一个cast节点然后没接任何线就会有reference。
所以请认cast节点不要用执行逻辑判断
除了cast之外,任何reference到其他class的BP节点或是变量也会造成跟cast
一样的结果。
除了会影响编译时间,cast也会影响到使用editor时使用的内存多寡。
Reference很重要,请谨慎的使用cast以及class reference。
以下列出一些范例
1. BP reference 到Pawn class
通常是没问题的,因为player 的class早就load好,并且会一直存在。
相同的想法,cast到一些主要的class通常也是没问题的。
2. 小规模的BP Cast到另一个小规模的BP。
通常是没问题的,因为够小。
3. 从BP cast到只有变量没有逻辑的BP
没问题,因为只有data所以这种BP编译很快
笔者:这边的变量不能包含class reference,否则还是会连到其他class。
4. 从一个常用的BP cast到不常用的BP
不妥,如果这个不常用的BP逻辑还很复杂就更不好了。
如果是反过来,不常用的BP cast到常用的BP还可以接受。
5. 系统重要的Class彼此互相cast
从内存的观点来说可以,但是这么作会造成你只改一个BP class,
其他class可能也要重新编译并存盘。
笔者:这种情况很不好,就是Circular reference了,基本上开发过程要完全避免。
改一个class会触发其他class要编译并存盘,这种情况会很难协同合作。
你本来只改class A,却要同事正在用的class B让给你存盘。
BP又不能merge,这样影响到他人的工作了。
Casting Tips
可以建立一套cast的规范,哪些class可以cast,哪些不行之类的。
使用C++ class作为BP之间的桥接。好处是效率,较干净的BP节点,
Cast到一个BP的parent class(C++)不会产生BP reference,是好的做法。
Interface也是用来解reference的好方法,其他BP只要reference interface就好,
不用reference BP本身。
因为直接检查actor是不是哪个class也会造成reference。
建议可以使用gameplay tag,以查询tag的方式来作判断。
笔者:其实cast规范不太有意义,花时间做这个不如用C++ class,
因为使用C++ class优点太多。
小总结cast技巧
使用C++/继承/Interface,加上正确的观念来管理reference。
有需要可以搭配GameplayTags
BP编译的Race Condition问题
Race Condition指的是两个以上的class互相有关系,甚至连initial的值也互相有关系
Initial的结果会根据即时class编译的顺序而有所不同
笔者:只要系统没有Circular reference这里面讨论的问题自然就消失
C++
C++的优点
C++可以轻易的把变量跟函式暴露给BP使用/呼叫。
这里没有建议任何C++/BP的使用比例,每个专案都有各自的特性,这个比例没有一定。
但是不管怎样你应该都先从BP开始学习,甚至精通BP。
这边提到一个点是即使是程式人员也要学BP,
因为程式做出来的东西毕竟会给BP的开发人员用。学习BP比较能够让彼此没有代沟。
即使只有很少部分的C++,也可以让你的专案流程更顺,更容易扩展,执行更有效率。
C++效率好,比较容易处理复杂的系统,比较容易处理数学运算式。
有些事情在BP是做不到/很难做到的,例如存盘读档,平台相关,特殊硬件等等。
在BP与C++之间找到一个平衡点是专案发展过程中很重要的项目。
BP的优点
BP非常善于作雏型验证(Prototyping)
BP在迭代开发(Iteration)是有效率的
BP的流程容易理解,有弹性,容易使用。
BP需要用到的时候才读取
笔者:BP内存这点其实不公平,虽然BP要用到的时候才读取,
C++是程式执行就读取,但是一个BP占的内存就可以塞超多C++ class。
C++与BP协同合作
建议大多数的BP class都继承自己写的C++ class开始,而非继承引擎内建的class。
哪些情况建议放在C++
1. 会在多个地方被呼叫的函式
2. 每个tick会呼叫的功能,尤其是牵扯到多个actor相关的功能。
3. 复杂,不好维护,容易出bug等功能
4. 明显日后会延伸,会长期维护的功能
5. 复杂且核心的功能,例如存读档,网络功能。
6. 重要的变量
哪些情况建议放在BP
1. 主要是关联到其他content asset的
2. 简单直观的功能
3. 非核心且单独功能的项目
4. 正在雏型验证且频繁修改的功能
5. 放进C++没有特别好处的功能(不影响效能,扩充性,不太有bug)
C++变量以及pure function可以有效的让BP变干净。
BP可呼叫的C++ Library可以用来被各个不同的BP呼叫且没有reference问题
即使大部分的功能都在C++,还是建议要提供各种事件让BP能够知道,或是修改行为。
C++函式加上修饰字BlueprintImplementableEvent可以让BP实作事件发生时的行为
Miscellaneous
下面说明一些有关BP的杂项。
如果因为某些情况把BP的连接线断掉,建议加上注解DOP(因为某些原因把线断了)
宣告这个断线是有理由的。
Pure function
好用且干净的BP节点,没有input/output exec节点。
Expose On Spawn
将变量宣告为Expose on spawn可以在生成时直接传入初始值
Call In Editor
让这个函式可以在Editor呼叫,实现editor的行为
Expose to Cinematics
让变量可以在Sequencer内取得。
Delete Unused Variables
可以自动将BP内没用到的变量删除。
Show 3D Widget
让vector可以在editor的viewport内看到。
Deprecate
宣告这个BP即将不被使用。
Bookmarks
可以记录BP graph的某个地方,方便追BP节点。
String Tables
可以透过.csv档制作的字串比对表格。不用直接在BP里面硬写字串。
对于localization(多国语言)跟开发都有帮助。
变量容器类型Maps/Sets
各种容器特性与使用时机在这边就不特别说明。
IsValid
用来检查物件是否合法,确保系统稳定的节点。
总结
以上两篇就是Unreal官方对于BP的深度说明,个人觉得很多项目都非常的实际好用
未来有机会可能会分享个人对BP/C++在本篇中没提到的理解~
作者: wangm4a1 (水兵)   2019-06-22 21:56:00
作者: jerryklu (鲁凯)   2019-06-22 22:18:00
作者: coolrobin (泳圈)   2019-06-22 22:44:00
未看先推
作者: diac3000 (diac)   2019-06-23 12:46:00
推!
作者: rickkcir (多果汁)   2019-06-24 15:05:00
推荐这篇文章
作者: damody (天亮damody)   2019-06-24 21:13:00
作者: SaxPenguin (平果)   2019-06-25 09:42:00
看完了推

Links booklink

Contact Us: admin [ a t ] ucptt.com