Unity中使用ulua的个人经验总结

热度 286052 2015-3-15 14:32 |个人分类:技术类Lua

Lua代码都是运行时才编译的,不运行的时候就如同一张图片、一段音频一样,都是文件;所以更新逻辑只需要更新脚本,不需要再编译,因而Lua能轻松实现“热更新”。Ulua是一款非常实用的unity插件,它能让unity支持Lua语言,而且运行效率还不错。下面就跟大家谈谈我用ulua的一些心得。

Ulua的使用流程一般为:

实例化LuaState对象(new LuaState())è加载Lua代码(LuaState. DoString(string))è调用Lua代码中的方法(GetFunction(string),LuaFunction.callFunction(string))。其中,加载Lua代码这一块,可以直接赋一段Lua代码字符串,也可以指定一个Lua脚本文件。为了热更新,应当采用第二种加载方法,即创建一个Lua脚本文件。由于Unity不支持扩展名为lua的文件,所以可将Lua脚本扩展名定为txt(纯文本文件),并用unity的TextAsset列表负责记录所有脚本文件。建议列表中给每个脚本搭配一个string类型的ID,这样凭此ID即可加载正确的lua脚本;另外在LuaState类中新增一个String类型的public成员,赋值为该ID。这样一旦某个Lua脚本在运行时报错,可根据输出的ID值判断是哪个Lua脚本有错误。

关于Lua里的预处理:

luanet.load_assembly("Assembly-CSharp")

luanet.load_assembly(‘UnityEngine‘)

Vector2 = luanet.import_type(‘UnityEngine.Vector2‘)

Vector3 = luanet.import_type(‘UnityEngine.Vector3‘)

GameObject = luanet.import_type(‘UnityEngine.GameObject‘)

luanet.import_type(‘System.Collections.Generic.List‘)

Debug = luanet.import_type(‘UnityEngine.Debug‘)

这些都是常用的Lua预处理,建议单独写个Lua脚本记录这些,以后加载其他Lua脚本前都先加载一下这个脚本。自定义C#类也是可以import的,import操作是Lua调用C#的前提。当然在C#中实例化的LuaState也可以预定义一些Lua全局变量,这都是在C#里完成的,比如:

[code]csharpcode:

void SetLuaData(LuaState lua)
{
       lua["transform"] = transform;
       lua["gameObject"] = gameObject;
}

预定义了两个变量,一个是transform,一个是gameObject。

关于Lua里的全局变量:

Lua里所有的字符串,如果不是关键字或者运算符,就都是变量;这些变量中,凡是没用local关键字修饰的,就是全局变量,反之,则是局部变量。每个LuaState对象,当它加载过Lua代码以后,它里面定义的全局变量,在这个对象生命期内是一直存在的。如果两次调用这个LuaState的某方法,第一次将某全局变量进行了修改,那么第二次,这个全局变量会在第一次修改的基础上继续修改。

关于Lua在Unity的适用范围:

虽然Lua可以负责Unity工程的任何模块,但是出于对游戏性能的考虑,尽量少的低频率的调用Lua,比如尽量少在Update函数中调用Lua、循环利用已经实例化过的LuaState避免浪费资源。对于那些不需要高效运算的模块,比如UI部分,就可以放心大胆的使用Lua。

关于Lua与NGUI的适配:

调用Lua的主要方式就是callFunction,而对于NGUI来说,一般都是按钮触发某C#脚本的函数,那么如何用按钮触发Lua的函数呢?这就需要有个C#脚本作为“中介”,这个“中介”需要有自己的LuaState实例,当执行“中介”的某个方法时,由该方法调用callFunction。至于具体调用Lua脚本的哪个方法,可以通过传参的方式告诉这个“中介”——修改NGUI的ButtonMessage类,加入新的public string LuaFunctionName成员,以后由它来制定要调用的Lua方法名就好了。而通过NGUI的UIButton等调用C#的方法,也是同理的(NGUI3.5.6版以后,可以给UIButton等等组件的触发方法添加参数了)。

关于Lua与SimpleJSON的适配:

SimpleJSON是一个开源的JSON库,这个详见之前的博客。由于Lua语言无法理解C#里面的属性,所以凡是SimpleJSON里的public A{get,set}这种,要新写一些接口函数返回它们的取值,以供Lua调用。而且Lua调用C#里经过很多重载的函数,也经常判断错误(这是个bug?),所以干脆多弄一些函数名,避免调用错误。

关于Lua与Lua之间的调用:

在Unity中使用Ulua,想要让两个Lua脚本彼此调用是很难的,需要通过C#作为“中介”,而且Lua不支持C#的泛型,所以不能用GetComponnet<类名>()的形式,只能用GetComponnet (“类名”)的形式去获取组件。两个Lua脚本相互传参也很麻烦,因为有了C#脚本作为“中介”,所以不能传tabel类型的参数,我的做法是将若干参数拼成一个json字符串传递过去,另一方再解json包。感觉有点蛋疼。不过这种情况并不多见,都是可以避免的(比如一个模块只用一个大Lua脚本,各自独立减少沟通)。

关于Lua编辑器:

个人使用的是notepad++,也有很多人用sublime,代码折叠这块notepad++更好一些,而sublime在功能上貌似更强大一些。

Unity编程的亲们,有没有在Unity运行状态下修改并保存了脚本,然后切回来Unity直接卡死的惨痛经历?使用Lua,你将告别这一现象,有木有心动呢?

时间: 2024-10-18 17:58:13

Unity中使用ulua的个人经验总结的相关文章

菜鸟学习 - Unity中的热更新 - Lua和C#通信

孙广东 2015-4-6 热更新我是个菜鸟,感谢网上的各位的奉献,这次又当一回搬运工. 准备: 1.了解Lua的语法 推荐书籍<Lua程序设计 第二版> 2.使用ULua插件进行通信 尽量早上真机.因为Bug问题特别多. 大杂烩: 更新LUa其实也是更新资源. Lua被看作一个资源么.Lua代码都是运行时才编译的,不运行的时候就如同一张图片.一段音频一样,都是文件资源:所以更新逻辑只需要更新脚本,不需要再编译,因而Lua能轻松实现"热更新".运行效率由于使用反射,所以成为它

【原创翻译】初识Unity中的Compute Shader

一直以来都想试着自己翻译一些东西,现在发现翻译真的很不容易,如果你直接把作者的原文按照英文的思维翻译过来,你会发现中国人读起来很是别扭,但是如果你想完全利用中国人的语言方式来翻译,又怕自己理解的不到位,反而与作者的愿意相悖.所以我想很多时候,国内的译者也是无奈吧,下次再看到译作也会抱着一些感同身受的态度去读.这是我第一次翻译整篇文章,能力有限,望见谅,翻译不好的地方也希望大家指出来. 其实ComputeShader在Unity中出现已经有蛮长的一段时间了,因为自己一直对Shader比较感兴趣,所

[Unity热更新]ulua学习笔记01:一个小坑

看了一下以前写的文章,发现都好水啊..我也想写出能真正帮到别人的文章,但没办法啊,自己的脑子太笨了..希望可以通过不断学习,终有一天能写出点好文章! 最近在学习unity中的热更新,既然大神都说ulua效率最高(就现在来说),那就学习ulua吧!首先要下载的是ulua的包,现在的最新版本是1.08,而且根据官网上说的,网上流行的1.03/1.05含有大量的bug,所以我选择了最新的版本,谁知道就掉进了第一个坑! 因为是菜鸟,所以先复制一下网上的代码看看效果如何,结果碰到这样的错误: 搜索了这些错

Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交:一些光线被物体吸收了,而另一些光线被散射到其他方向. 最后,摄像机吸收了一些光,产生了一张图像. 在光学中,我们使用辐照度来量化光.对于平行光来说,它的辐照度可通过计算在垂直于l的单位面积上单位时间内穿过的能量来得到.在计算光照模型时,我们需要知道一个物体表面的辐照度,而物体表面往往是和l不垂直的,我们可以

在Unity中使用事件/委托机制(event/delegate)进行GameObject之

欢迎来到unity学习.unity培训.unity企业培训教育专区,这里有很多U3D资源.U3D培训视频.U3D教程.U3D常见问题.U3D项目源码,[狗刨学习网]unity极致学院,致力于打造业内unity3d培训.学习第一品牌. 一对多的观察者模式机制有什么缺点? 如果你对如何在Unity中使用事件/委托机制还不太了解,建议您查看我的前一篇文章:[Unity3D技巧]在Unity中使用事件/委托机制(event/delegate)进行GameObject之间的通信 在前一篇博客里面,我们写到

unity中三种调用其他脚本函数的方法

第一种,被调用脚本函数为static类型,调用时直接用  脚本名.函数名().很不实用-- 第二种,GameObject.Find("脚本所在物体名").SendMessage("函数名");  此种方法可以调用public和private类型函数 第三种,GameObject.Find("脚本所在物体名").GetComponent<脚本名>().函数名();此种方法只可以调用public类型函数 unity中三种调用其他脚本函数的

关于Unity中的NGUI和UGUI

用Unity开发2D游戏,有三套关系 1.GUI:Unity本身的对象 2.NGUI:以前在Unity中广泛来做2D的,是第三方的包,需要安装 3.UGUI:Unity5.X后,Unity找到NGUI的作者,开发了UGUI,变成内置于Unity中的包,官方主推 所有的元素都在Unity的UI工具栏 3D做2D游戏的方法: 1: 使用正交摄像机;2: 使用透视摄像机,将2D元素移动到合适的距离. 例如设计分辨率为 960x640, 得到在3D世界里面一个图片的大小w*h米,将这个图片移动到一定的距

Unity中使用协程进行服务端数据验证手段

近期在做项目中的个人中心的一些事情,用户头像上传,下载,本地缓存,二级缓存,压缩,这些都要做,麻雀虽小五脏俱全啊,也是写的浑浑噩噩的, 当我们在上传用户头像的时候,向服务端发送上传头像请求之前,一般都会做一次验证,向服务端获取token验证信息,来确保非法上传,如果不做这个那么会有非法用户上传非法图像,使你的服务器 带来未知的灾难. 而验证的逻辑很好写,并没有什么难度,比如: Server.SendMessage("获取token"); Client.Receive(string to

C#中的yield return与Unity中的Coroutine(协程)(下)

Unity中的Coroutine(协程) 估计熟悉Unity的人看过或者用过StartCoroutine() 假设我们在场景中有一个UGUI组件, Image: 将以下代码绑定到Image 1 using UnityEngine; 2 using System.Collections; 3 using System.Threading; 4 using UnityEngine.UI; 5 6 public class CoroutineDemo : MonoBehaviour { 7 8 //