最近新学蓝图编程。。还没看蓝图VM代码,有些点不保证准确
本文主要是从使用角度,分析你为什么需要学习蓝图,蓝图适合做什么,不适合做什么
最后 Bonus,跟一下 Blueprint Pipeline,梳理一下蓝图的知识结构
Blueprint - Wikipedia
蓝图(英语:Blueprint),港澳地区又称“蓝本”或“蓝纸”,是工程制图的原图经过描图、晒图和薰图后生成的复制品,因为图纸是蓝色的,所以被称为“蓝图”。蓝图类似照相用的相纸,可以反复复制新图,而且易于保存,不会模糊,不会掉色,不易玷污。
蓝图这个词的本义很接近 Prefab,预制体,蓝图描述一个东西的结构和行为,可以多次拷贝,实例化为具体的实体 Entity
UE 蓝图是一种资源,把引擎暴功能以可视化脚本的形式暴露出来
另外,UE3 时代的可视化脚本叫做 Kismet
实现原理,基本综合了常见脚本方案的做法
说下第三点,主要是和 Lua 有区别
Lua 是通用的,有自己的对象模型,但是接入每个引擎,都需要做一个类型映射,记录额外的类型信息,这是有开销的,想一想各种 SDK 的 XXXVector3 类
蓝图是直接在 UE 内核上实现的,因此只能 UE 用,没有类型映射的开销
如果需要 UE 蓝图编辑,在自家引擎跑,就需要实现一个 Compiler,把蓝图翻译成自己引擎的格式,工作量和坑不小
脚本对非程序的游戏开发技能提升是有积极意义的
脚本本质是把 Compiler 和 Linker 集成到 Engine Runtime,这样只要下载游戏就可以编程了,不需要装Visual Studio 或者某种编译工具链(一般很重型),对于UE蓝图,则是把 IDE 集成到 UE Editor
蓝图目前的功能几乎覆盖了 Gameplay 开发,还包含联网,理论上开发玩法可以靠纯蓝图完成
有一些纯蓝图开发的案例,作者是非程序,比如谌嘉诚的《死寂》
总的来说,蓝图降低了编程的门槛
对程序员,理论上掌握 C++ 和 Lua,不需要学蓝图
所以其实问题是,没时间学蓝图,怎么用最小成本,学到能看懂别人的蓝图的程度
笔者采取的策略,是把蓝图翻译成熟悉的 Lua
学习一门语言关键在于理解语言的语义,或者说VM是如何实现的
说白了,就是策划才写蓝图,蓝图节点由程序实现,不要搞得很复杂
让策划写脚本,本质是程序和策划工作的解耦,策划提需求,策划自己实现,自己维护和迭代
这个边界定在哪,其实取决于团队策划的平均水平,没有经验可以从简单做起,如前所说,这是一个机会
说白了,复杂的东西都不适合。。这里针对的是大型项目工程,需要 scale,需要快速定位问题,后期低成本解决性能问题
反过来说,适合做 Demo,但是 Demo 无法 scale 到大项目
选择脚本语言需要优先考虑的是性能上的 scale,VM 的性能决定了能承载多复杂的代码(指令吞吐量),开发写得很爽,性能不行,最后还是要 C++ 化
然后是工程上的 scale,不解释了。。
蓝图在这两点上和 Lua 基本没法比,所以蓝图 VM 也没有深入理解的必要,别用蓝图就完了
重构的问题,拿到 Lyra 的代码,把 C++ 代码的 “Lyra” 全局替换成自己项目前缀,Boom,蓝图爆炸了,因为蓝图里都还是引用的 LyraXXX 类型
移植的问题,这和 UE 插件本身也有关系,但是可以看出,即使是很简单的情形,也很麻烦
Lyra 要接入一个背包插件,要把插件中的 ExamplePlayerController(蓝图实现) 移植到 LyraPlayerController(C++实现) 上
如果都是 C++,把 ExamplePlayerController 代码复制粘贴,合并到 LyraPlayerController 下面,再全局文本替换 ExamplePlayerController 为 LyraPlayerController,ez,10min 搞定
蓝图呢?蓝图的属性和函数要拷贝过去吧,直接CV,Boom,编辑器 Crash,最后找了个插件拷贝过去了
拷贝过去还是编译不了,为什么呢,因为蓝图是有类型的,ExamplePlayerController.MyMethod 节点和 ExamplePlayerController 类绑定了,要把原来的节点删掉,再拖出来新节点 LyraPlayerController.MyMethod ,所有连线重新连一遍,有的节点要连五根线。。
这样的操作,需要搜索引用,然后一个一个节点去改
项目用蓝图开发一个月了,补充一下多人开发的问题
项目起点是一些 Demo 的混合,有大量蓝图脚本,多人在一个模块上开发时非常痛苦
多人开发阻塞
Crash 率
编辑效率
这里说无法,确切的说是不可用,有蓝图 Diff,有全局搜索,效率低得没法用
对比Lua的文件列表
说白了,可用性低,开发效率低
语言 BUG 率要求很高,是程序员的 trust base,出了问题老是需要怀疑是不是语言出了 BUG,定位问题的效率会大打折扣
BP 用于扩展
Actor和Component其实也属于继承C++类,BP Actor对标Unity Prefab
EventGraph对标Flow,是BP相比于C++和Lua最大的优势
BP属性
BP类别
C++ <=> BP
BP <=> BP
标准库
UE 里修改蓝图前点一下保存,有其他人 checkout 了就别改了(你被阻塞了)
蓝图本地化
这个生成代码,更像是 IL2CPP,只是打包时用,开发还是蓝图编程
蓝图 Merge
经过测试,不好用,并不能自动 Merge,所以只是一个 Diff,而且 Diff 也很糟糕
UnLua 可以完全替代蓝图,可以增量地把蓝图 Lua 化
一个Widget变量类型从UniformGrid 改成 Grid
然后就break了,要全部重新连,哪怕两个类型都有ClearChildren接口(以及AddChildToUniformGrid
AddChildToGrid),但是ClearChildren不是两个类的基类里的,就会break
语言有类型系统本身是帮助重构的,但是这里却反而很麻烦
实际开发中,编辑器崩溃率不低,一部分是UE引擎问题,一部分是项目人多了,用法可能超出UE的考虑
使用上,建立索引很慢,搜索相当于全局搜索字符串
曾经查一个偶现的鼠标Cursor没了的问题,在蓝图里搜 PlayerController.bShowMouseCursor,非常痛苦,最后还是没有定位问题
没有看过底层实现机制