注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

重新出发的阿赵

阿赵的博客

 
 
 

日志

 
 

在Unity项目内用lua开发的一点经验  

2017-11-12 11:37:33|  分类: Unity教程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
手游现在一般都有热更新的需要,而C#是需要编译的,虽然说也可以通过一些方式热更新,比如dll之类,但更多人会选择使用lua写逻辑来达到能热更新代码的目的。
阿赵我使用lua做了2个项目,第一个项目是用slua,第二个项目是用tolua。
两种lua支持的优缺点我在这里不做评价,给我的感觉是各有优缺点。我主要想说说lua本身在Unity项目使用的一些问题。
使用lua有很多优点:
首先它是不需要编译的。如果是用完全C#写,在项目越做越大,代码越来越多的时候,每次写完C#代码之后,都要等待Unity编译很长一段时间才能运行,才能看到效果。但用lua写,在写完lua之后,完全不需要等待,就可以运行,甚至还可以一边写代码,一边通过某些方法刷新某个lua文件来直接起效果。
然后它是弱类型语言,在有很多比较便利的写法。
最后,它可以直接真机上修改调试。虽然大家在项目最终的时候都会把lua加密来使用,但在开发的过程中,可以在lua加载的地方写一个开关,来读取没加密前的lua文件加载。这样,就可以直接把lua代码拷贝到手机上面去,然后买一个蓝牙键盘,在手机上面装一些好用的代码编辑器,就可以直接在手机上面修改代码然后运行了,不需要频繁的发布安装包看效果。
使用lua也有一些缺点,首先是lua本身的效率肯定是没有C#那么高的,然后lua的在某些处理上比较弱,比如在处理字符串方面的库比c#的弱很多。最后,不论是哪种lua插件,不论是通过反射的还是导出接口文件的方式,在调用Unity某些原生的api方法时,效率都不如C#直接调用那么高,有些甚至是会低很多的。
下面来说说使用时的一些比较影响执行效率的问题和使用上要注意的问题:
1、lua和c#互相调用的穿梭消耗
所谓的穿梭消耗,举例说就是,在C#端调用lua的方法,消耗是比在lua端直接调用lua方法高的。由于lua端处理某些东西没有C#方便,所以我们会有这样的做法,在C#写一些方法,然后lua直接调用,C#也会回调lua的方法。这样做本来是没什么很明显的问题。但如果是某些方法是写在循环里面,或者update里面,会每帧调用很多次的,这种穿梭的消耗就会变得明显。
我在做第一个项目的时候,事件机制写了2套,一套是可以在C#和C#或者C#和lua之间使用的,另外一套是在lua和lua之间专用的。我在做第二个项目的时候,为了能让lua和C#两边的事件机制统一,是在c#端写了一个统一的事件分发方法,然后lua和C#就可以不需要关心事件的针对对象随便抛。但后来我发现这样做了之后,在两端之间抛事件的消耗还是有点明显,因为项目内基本都是靠各种事件来调用逻辑的,事件的数量比较多。后来我想想,还是在做第一个项目的时候的做法可能会比较合理一点。毕竟因为大部分逻辑都是在lua调起的,而统一事件又写在C#,这样绝对的穿梭数量就会比较高。
2、lua的循环 和update
这是我自己的感觉,在lua端做循环的效率是比c#低的,特别是循环的数量很大的时候。
然后是每帧调用的update方法。在lua端做update的方法有好多种,但最终其实都是从C#里面注册一个在Update里面调用的统一方法,然后调起lua端注册的update方法来达到update的效果。包括tolua自带的lualooper里面的update也是这样做的。
我现在是尽量避免在lua端的update里面做太多的逻辑,如果一些很必要的逻辑,我会考虑移动到c#端去做。至于循环,为了能尽量减少循环遍历,我会通过在缓存数据的时候做多一些分类的列表,尽量能让单次的循环次数变少一点。至于不要在update里面写循环,这已经和lua本身没什么关系了,在C#也要尽量避免的。
3、对于Unity组件的操作
在lua里面能实现100%的unity功能,因为不论是哪一种lua插件,都可以把Unity的Api完全导出给lua使用。但问题是,对于一些组件的操作,在lua这边的效率是非常的低的,下面举几个比较明显的例子:
首先是GetComponent和AddComponent,这个在lua那边频繁的获取,特别是通过组件名称的字符串获取,消耗是比较大的。可以考虑改成通过type来获取,或者直接通过绑定类型来获取。比如直接挂一个C#的脚本在对象上面,然后上面获取了各种需要的Component作为变量,然后lua那边只需要获取到C#的脚本对象,就能从上面获取到需要的各种Compnent。
然后是lua操作UGUI的效率也是比较低的,比如设置RectTransform的position的消耗,是在C#端同样操作的好几倍。设置Canvas相关的一些方法,也是效率比较低的。本来lua一般就是用来写业务逻辑,和ui的关系会非常密切的。但由于效率其实不是很高,所以一些特别频繁的操作,比如想通过lua的update不停改变ui位置来做动画,最好还是改成在c#那边实现,然后用lua只是调起动画的开始和结束。
lua操作Vector2或者Vector3之类的变量消耗也是比较大的。频繁的操作还会引起内存回收。
4、对于变量类型的操作
lua原生的数字类型只有number,旧版的number类型只支持32位,新版的已经支持64位。需要注意的地方是,如果需要把lua的number传送给C#端用,那么传到C#端的类型其实是double,C#端必须保证接收的方法变量是double型,不然会报错。
5、对于随机数的操作
lua原生的math里面的random方法,其实是伪随机,如果不在随机之前先设置一下随机种子,那么初次随机出来的结果是一样的。所以可以考虑在调用随机之前,先用当前时间戳作为随机种子传进去。

在我做第一个lua项目的时候,我想得是很伟大的,我想做一个100%能热更新的游戏,所以游戏的95%以上的逻辑都使用了lua来写,包括了很复杂的热更新流程、json解析、寻路算法、状态机、技能时间轴播放等都是用lua直接实现了,在c#端只写了socket连接和收发协议,还有诸如位运算之类lua没有直接提供的方法。其实这个项目是做完没什么功能上的问题,但效率上却存在了一定的问题。后来想想,这样100%热更的游戏不是不能做,但不适合用于做arpg这种频繁运算的游戏,如果是做回合制或者卡片类游戏,战斗的逻辑是比较固定而且不会很频繁的,这样的做法完全没有问题的。可惜我做的是APRG,所以在太频繁的逻辑交互时,lua的效率还是会存在一定的问题。于是现在的项目,就改为了复杂的算法逻辑和操作Unity组件的方法还是写作C#,只是由lua作为调起者。然后UI相关的逻辑,都由lua来写。这样只要在上线前能确保C#提供的基础方法不会有太大的bug,其他的功能还是可以正常的热更新的。
  评论这张
 
阅读(22)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017