高效使用lua作为业务开发语言的秘诀在这里!

2018-09-06 17:54:18 浏览数 (1)

导语

你还在使用c 开发UE4吗?会不会感觉太慢了?会不会感觉编译一次就可以去楼下喝杯咖啡了?会不会感觉总是提心吊胆,搞不好什么时候就crash了?现在不用发愁了,slua出unreal版本了,在unity上广泛流行的slua发布了unreal版本,还是那么强大,还是那么好用,你还等什么,赶快上船吧。

1 为何做unreal版本?

目前unreal提供的开发语言包括c 和蓝图,但这2个开发语言都或多或少存在一定的问题,对于c 来说,最大的问题是c 开发人员越来越少,精通c 开发的同学更少,而且c 本身并不是描述业务的最好语言,稍微不留心就容易崩溃或者内存泄露,这是不能接受的,其次unreal下修改c 编译时间太过漫长,如果还修改了header文件,那每次编译真的可以去喝一杯咖啡了,工作效率不高,还有就是调试,如果你想快点运行,选择dev build,则势必丢失一些调试信息,或者出现错误调用栈,或者某些局部变量看不到信息,或者某些断点失效,如果你选择debug build,则启动速度慢,运行慢,好好的一个i7多核计算机,搞的比乌龟都慢,如果正好赶上项目上线,问题频发,想死的心都有。

如果你选择使用蓝图,我只能说作为程序员你骨骼清奇,这玩意都能用于实际业务开发,跑跑demo,做做prototype还行,一般没有业务用蓝图作为主要开发语言用于产品,它最大的问题是不能merge,无法多人协作开发;稍微修改一些接口,某些slot就要重新链接;稍微大一点的蓝图程序看着都头晕。一般蓝图都是作为配置或者流程描述来用。

有介于此,做一套脚本化的开发语言是必须的。

2 Unreal自身提供lua支持?

对,你没有看错,Unreal早期版本其实内建支持lua,只需要自己开启一个宏WITH_LUA,然后重新编译unreal引擎,就可以开启lua,但这个功能在unreal仅仅是概念演示,而且从某个版本之后也不再维护了,实际使用起来也有很多问题,更重要的是,这个功能需要重新编译UE4,这对于大多数拿着引擎就是开箱即用的开发组,重新编译引擎是不现实的,所以我们需要提供一个扩展的插件,不用重新编译,也能方便使用lua来开发。

有介于此,slua 的 unreal 版本诞生了,当然你会问slua什么鬼?嘿嘿嘿,slua就是在unity下广泛流行的lua开发插件,适用于在unity引擎使用lua作为开发语言开发游戏业务,而作者就是我本人,那理所当然,我有必要做一个unreal版本方便slua的用户可以快速迁移到unreal下,因为我是一个负责任的开源软件作者。

3 slua unreal版本提供什么功能?

这说起来就有点激动了,说了这么多也总算进入正题了。

1)对于蓝图类和蓝图方法的调用 什么是蓝图类和蓝图方法呢?就是所以标记了了UCLASS和UFUNCTION的类和函数,UE4为这些类和函数提供反射能力,通过使用反射,slua可以方便调用这些函数,蓝图自己也使用这些反射能力来支持蓝图调用,所以理论上我们使用这些能力来供lua调用,不会比蓝图自己更慢。

2)支持使用lua function作为蓝图的事件代理

在蓝图里支持代理,例如:

这个OnClicked就是代理,可以绑定一个c 函数,或者绑定一个蓝图slot用于触发事件调用函数,slua支持传入一个lua function作为代理函数,调用进入lua函数。例如:

3)对于非蓝图类和非蓝图方法,支持基于静态代码生成的自动导出 和 基于模板展开的手动添加

在实际项目中,我们有很多代码并非是蓝图类,但也需要在lua中使用,比如最常见的FVector,这个类并不是蓝图类(一般蓝图类都是U开头的类),但我们需要在lua中使用FVector来完成位置、方向的计算,我们就需要把FVector导出到lua中使用,为此slua附带了一个工具,通过这个工具可以自动化的导出我们指定的c 类,并生成对应的静态代码,这个工具是基于libclang,它使用libclang产生的反射信息来完成代码生成,这点上类似Unity版的slua,最终生成的代码如下:

可以看到slua将FVector的成员方法都导出了,整体的代码风格与slua unity版本类似。

除了支持静态代码生成的导出,也支持基于可变参数模板的导出,这需要手动添加简单的导出代码,例如:

slua会基于可变参数模板自动展开代码,产生正确参数解析和函数返回值,生成对应的导出函数,不需要对原始c 类做任何注入式的修改。

4)支持数学运算符重载

正如上面提到的FVector,它需要若干计算功能的函数,如果是突兀的Add,Mul看起来很奇怪,而且本身FVector在c 层面也支持运算符重载,所以slua也将这部分能力导出到了lua里,支持在lua层面的运算符重载,方便代码书写。

5)从蓝图直接调用到lua并返回任意返回值

一般使用lua的情景是从c 代码调用lua,但蓝图提供了热更新的能力,有时候我们希望通过蓝图的热更新能力来启动lua代码,这个时候就需要从蓝图调用lua函数,同时返回lua返回值到蓝图,例如有如下lua函数:

我们可以构造如下蓝图来调用lua

我们可以传入任意数量的参数,任意参数类型,并返回任意个数的返回值。

6)支持out类型的蓝图参数和引用类型的c 参数作为返回值

与c#类似,蓝图也支持out类型的参数用于返回多余的返回值,而c 这里,一般我们使用非const引用来返回多余参数(当然也可能不),slua支持这种使用情况,对于out类型的蓝图函数参数会额外返回,对于非const的函数参数也会额外返回,对于c 这里,slua无法区分函数设计时的语义,只要非const的引用类型,都会额外当做返回值返回,当然你可以选择忽略不使用。

7)通过静态代码生成,导出了UE4所有的enum,并使用int支持enum参数

8)支持扩展方法

类似c#的extension method,slua unreal也支持扩展方法,什么是扩展方法呢?比如一个UUserWidget这个蓝图类,存在如下方法:

它并不是蓝图方法,但存在在蓝图类里,我们可能非常需要这个函数能够导出到lua使用,但我们又不想为此修改引擎代码,添加一个UFUNCTION标签,这时我们可以做一个扩展描述:

这样就为UUserWidget添加2个扩展方法,这2个方法可以在lua侧被调用,可以看到第一个GetWidgetFromName方法直接使用UUserWidget的成员方法,第二个RemoveWidgetFromName方法则是手动实现了一个版本,通过这样描述,我们不需要修改UE4引擎就可以为UUserWidget添加扩展的lua方法,非常方便。

最后我们看一个完整使用demo代码:

目前slua unreal持续开发升级中,更多功能不断推出,如果你正在做unreal游戏?如果你正在考虑unreal下如何热更新?如果你正在考虑unreal下的脚本解决方案?不妨试试slua unreal。

4 使用案例

说了这么多,大家一定会问,你吹的那么牛逼,到底有没有项目用?答案是 slua-unreal 已经集成在潘多拉智能营销解决方案,用于支持腾讯多款游戏业务,通过了DAU千万级的产品测试,上线质量稳定,大家可以放心使用。

5 项目地址

slua-unreal已在Github上开源, 开源地址:

https://github.com/Tencent/sluaunreal

大神力作,欢迎Star,Watch,fork,pr!

作者简介

庞巍伟,腾讯移动客户端技术专家、技术总监,slua作者,14年游戏开发经验,对端游、页游、手游都有丰富开发经验,曾参与《梦幻西游》《天下贰》《神将三国》等游戏项目的全程开发工作,目前负责腾讯IEG潘多拉 智能营销解决方案的技术建设、架构工作。

0 人点赞