tolua 怎么实现unityunity 逻辑代码分离

【Unity3D】让你的游戏支持热更新
我的图书馆
【Unity3D】让你的游戏支持热更新
&作者:蝎子马戏团& &来源:
1、在Unity中引入lua的主要原因:& &&&1.1,Unity不支持代码热更新& &&&C#在ios平台不支持热更新,在Android平台热更新也比较麻烦,而lua支持热更新。& & 1.2,为了能够前后台复用关键逻辑代码& &&&Unity前台使用C#,后台使用C或C++,属性计算和战斗系统代码无法复用,通过lua可以方便实现前后台关键逻辑代码共用。 2、lua插件的选择:& & 2.1 UniLua& & 云风团队的作品,纯C#实现,但使用起来很麻烦,比较鸡肋。& &&&2.2 uLua& & & &&&uLua是 Lua 、LuaJIT 、LuaInterface的集合,Unity主流的lua插件, AssertStore上售价40美刀。& & C#调用lua脚本和从lua脚本中访问C#对象都方便,接下来我们简单了解一下uLua,然后通过一个简单的Demo来深入了解uLua的使用。 3、C#调用lua脚本& && && &基本保持了和C++相同的调用方式,对于用过tolua++的同学非常亲切& && & // 初始化lua脚本 //FLuaMgr.Instance.Init();
// 调用Test.lua中的 lua脚本函数//FLuaMgr.Instance.PCall("Test.ChangeMyClassProperty");
4、lua访问C#对象属性及函数& && && &uLua利用.Net的反射机制,直接从dll中导出C#类定义。& && && &这一块功能是通过Lua.cs实现的,具体实现机制比较复杂,我们看一个简答的例子:& && && &4.1 导入C#类UnityEngine& &&&= luanet.UnityEngineSystem& && && & = luanet.System
--- UnityEngine Classes---Debug& && && &&&= UnityEngine.DebugGameObject& && &= UnityEngine.GameObjectCamera& && && & = UnityEngine.CameraTransform& && & = UnityEngine.Transform
--- Our Classes ---luanet.load_assembly('Assembly-CSharp')MyClass = luanet.import_type('MyClass') & && & 通过这几句代码,我们就将UnityEngine的Debug、GameObject、Camera、Transform类导入进来了,此外将我们自定义的C#类MyClass也导入进了lua。这比用tolua++导出C++对象简单多了。& && &&&4.2 在lua使用使用C#导入类local myClass = GameObject.Find("MyClass"):GetComponent("MyClass");
myClass.DisplayName = "ChangedName From Lua";local box1 = myClassrawBox(1); & && && &GameObject .Find和GetComponent是Unity常用函数,通过uLua可以在lua中直接访问,这是uLua的重要优势。& && && &此外我们定义类MyClass的属性和函数也可以同样方便的调用,这样扩展起来非常方便。
5、加载lua脚本的优化& && && &创建一个LuaState, 然后使用LuaState的DoString就可以加载lua脚本;LuaState luaState = new LuaState();luaState.DoString("print('hello world')"); & && && &这样虽然可以加载lua,但是这并不能满项目需求,笔者封装了一个FLuaMgr& && &&&在FLuaMgr的Init函数中加载lua文件下的所有lua文件: // 直接读取TextAsset//private bool DoDirFilesByTextAsset(string path){& & TextAsset[] luaCodes = Resources.LoadAll(path);& & for (int i = 0; i & luaCodes.L i++)& & {& && &&&string fileName = luaCodes.& && &&&//Debug.Log("FileName=" + fileName);& && &&&int prefabEnd = fileName.LastIndexOf(GenLuaFileEnding); // 判断是否是lua文件 //& && &&&if (prefabEnd &= 0)& && &&&{& && && && &FDebug.LogWarning("FileName=" + fileName + " is not a lua file!");& && && && && && &&&}
& && &&&DoString(luaCodes.text, fileName);& & }& & // 卸载lua脚本文件 //& & Resources.UnloadUnusedAssets();& &} & && &5.1 Unity 只能识别.txt文件文件的解决办法& && & 在Assets/Lua 文件夹编辑lua脚本,然后通过ConvertToLuaTxt 转化到Assets/LuaGen文件夹下。具体内容参考Demo中的ConvertToLuaTxt.cs 6、Unity中嵌入lua的Demo介绍& && && &将附件中的uLuaExample.unitypackage 导入到一个空的Unity项目,然后打开LuaTest.unity,直接运行,lua脚本调用MyClass的函数绘制若干个矩形、球和圆柱体。-- 调用C#对象的函数function DrawSomeBoxes()& && && && &&&-- 直接调用GameObject的导出函数Find,类导出查看ImportClass.lua& && && && &&&local myClass = GameObject.Find("MyClass"):GetComponent("MyClass");
& && && && &&&-- 调用我们的C#类MyClass.DrawBox(float size)& && && && &&&local box1 = myClassrawBox(1);& && && && &&&box1.transform.position = Vector3(-5,-2.5,0);
& && && && &&&local box2 = myClassrawBox(1.25);& && && && &&&box2.transform.position = Vector3(-5,-1.0,0);
& && && && &&&local box3 = myClassrawBox(1.5);& && && && &&&box3.transform.position = Vector3(-5,1.5,0);end & && &&&执行效果图:& && && &
& & & & & & & & & & & & & & & & & && && &创建对象和位置排列逻辑由Test.lua实现。7、lua执行效率& && && &7.1 加载所有lua脚本的消耗& && && && && && & 笔者所在的项目有13个lua文件,lua脚本总行数1127行。& && && && && && &
& & & & & & & & & & & & & & & & & && && && && && & 在华为荣耀3手机上初始化lua平均耗时270ms。& && && &7.2 执行简单的lua函数的效率:function SimpleLuaFunc()& && && && &&&local id = 1;& && && && &&&if (id & 1)& && && && &&&then& && && && && && && && && & print("id & 1");& && && && &&&endend & && && &
& & & & & & & & & & & & & & & &
一次简单的lua调用平均耗时9微秒,性能在可接受的范围内。范围内。
[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢tolua 怎么实现unity逻辑 _ 自贡人才网
tolua 怎么实现unity逻辑
但是支持WP平台(其他平台也支持)。但是缺少tolua c#的支持。目前有对他的改进。但是ulua因为底层使用luajit,所以如果ulua支持WP平台需要第二种原生luavm的底层库,像C#ToLua。所以追求效率的,这个对于项目开发我认为暂时比性能重要。 看看权威的解释,因此效率略低于ulua。个人比较看好Slua的发展!很多人在用、Slua,请选用ulua,我是新手不了解,都是文件资源,不运行的时候就如同一张图片。 Lua被看作一个资源么,因为c版本底层用的原始的luavm(非luajit)。网上还有说nLua的:ulua包含两种c模式(luajit版+原生luavm版)。但是Ulua是很成熟的,因而Lua能轻松实现“热更新”、一段音频一样,它支持全平台。运行效率由于使用反射,不需要再编译。nlua包含2种模式(KeraLua c版本)(KopiLuac#版本),所以成为它与生俱来的诟病,加之tolua c#提供了直接访问渠道,而luajit目前不能在WP平台使用,很多坑都已经被人采完。当然了还有李总的L#走的就不是Lua的路;所以更新逻辑只需要更新脚本。Lua代码都是运行时才编译的更新LUa其实也是更新资源
192;iOS&#47目前ulua已经支持ZeroBraneStudio的调试功能:要调试的lua需要处于打开状态.Examples&#92.start(&#39。(3)运行例子uLua&#92.cs LuaScriptMgr:现在可调试平台包括WIN&#47.cs等4个文件;MAC/Start Debugger Server,测试步骤.168。zbstudio停止调试的时候。老版本or cstolua需要替换底层库。当前测试例子只支持WINDOWS。
真机调试方法;mobdebug&Lua&#92,单击菜单Project&#47。就能支持了。
感谢大神tangram发现并亲测;);LINUX&#47.112&#39.lua 需要根据自身配置路径(2)打开zbstudio。
第一个lua脚本里面 加上 require(&quot.cs Lua,先停止unity,会关掉Android全平台;04_ScriptsFromFile&#92,就不会关了.cs LuaS) :(1)打开uLua&#92。PS.217,并且对比更新 LuaDLL
更新LUa其实也是更新资源。 Lua被看作一个资源么。Lua代码都是运行时才编译的,不运行的时候就如同一张图片、一段音频一样,都是文件资源;所以更新逻辑只需要更新脚本,不需要再编译,因而Lua能轻松实现“热更新”。运行效率由于使用反射,所以成...
目前ulua已经支持ZeroBraneStudio的调试功能。老版本or cstolua需要替换底层库,并且对比更新 LuaDLL.cs LuaScriptMgr.cs Lua.cs LuaStatic.cs等4个文件。就能支持了。 PS:现在可调试平台包括WIN/MAC/LINUX/iOS/Android全平台。 真机调试方法:...
返回主页:
本文网址:http://www.0813job.cn/view-.htmlToLua & LuaFramework_UGUI学习笔记 - 简书
ToLua & LuaFramework_UGUI学习笔记
由于网上关于Unity Lua学习的资料较少,本人也是刚入门U3D不久,现在项目准备基于LuaFramework用Lua做热更新开发,最近几天看了ToLua官网的文档说明,研究了一下C#与Lua的交互并做了一些尝试,发现实际入手还是遇到了很多配置文件,方法调用的坑,并根据学习资料做了一些整理,方便初学者参考,好了 废话不多说,进入正题,由于比较基础大神绕过,不喜勿喷!基础部分:解决的问题更新频繁,而IOS审核长IOS无法用DLL反射机制去做代码更新如果无热更新,客户端每次都需要重新下载一次安装包。用户体验不好解决发布包的容量问题,一切都可以增量下载原理首先要清楚Unity的打包原理,也就是AssetBundle的打包机制,他会把prefab打包成.asset格式作为传输的数据。通过校验文件的MD5值来判断是否需要更新,如果需要更新则下载差异文件。lua属于解释性文件所以能通过www直接下载到本地,通过C#与lua交互,把逻辑写在lua里,从而实现代码热更新。注意记得加密lua。实现方案这里我推荐LuaFramework 这个框架(下简称tolua),以上内容他已经完全封装好,包括上述没提到的CG的一些操作。我们只需要在tolua里面写属于自己模块部分的逻辑就能简单的实现热更新。Tolua学习简介tolua#是Unity静态绑定lua的一个解决方案,它通过C#提供的反射信息分析代码并生成包装的类。它是一个用来简化在C#中集成lua的插件,可以自动生成用于在lua中访问Unity的绑定代码,并把C#中的常量、变量、函数、属性、类以及枚举暴露给lua。它是从cstolua衍变而来。从它的名字可以看出,它是集成了原来的tolua代码通过二次封装写了一个C#与tolua(c)的一个中间层。基础要想了解tolua#是如何集成的我们需要对C#的一些特性有一些了解,比如了解C#与原生代码交互的方式等。,我们假设读者已经对lua和tolua++有一个比较熟悉,我们略过lua与c或者C++的交互方式,主要介绍一些C#的特性,来帮助我们接下来分析tolua#的集成原理。C#特性AttributeAttribute 是一种可由用户自由定义的修饰符(Modifier),可以用来修饰各种需要被修饰的目标。特性Attribute 的作用是添加元数据。元数据可以被工具支持,比如:编译器用元数据来辅助编译,调试器用元数据来调试程序。Unity以及tolua#中就会用Attribute来辅助做一些事情。值类型与引用类型只所以要提这两个概念,是因为很好得理解这两个概念有助于我们写出比较高效的C#代码。我们知道,C#中的每一种类型要么是值类型,要么是引用类型。所以每个对象要么是值类型的实例,要么是引用类型的实例。引用类型和值类型都继承自System.Object类。不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即直接继承System.ValueType。作为所有类型的基类,System.Object提供了一组方法,这些方法在所有类型中都能找到,其中包含toString方法及clone等方法。System.ValueType直接继承System.Object,即System.ValueType本身是一个类类型,而不是值类型;System.ValueType没有添加任何成员,但覆盖了所继承的一些方法,使其更适合于值类型。例如,ValueType重写了Equals()方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。
简单了解了值类型与引用类型那么我们下面来看下C#中的装箱和拆箱的概念。装箱和拆箱装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作。1.
装箱在值类型向引用类型转换时发生2.
拆箱在引用类型向值类型转换时发生```object objValue = 4;int value = (int)objV```上面的两行代码会执行一次装箱操作将整形数字常量4装箱成引用类型object变量objValue;然后又执行一次拆箱操作,将存储到堆上的引用变量objValue存储到局部整形值类型变量value中。同样我们需要看下IL代码:```locals init ([0] object objValue,[1] int32 'value'//上面IL声明两个局部变量object类型的objValue和int32类型的value变量IL_0000: nopIL_0001: ldc.i4.4 //将整型数字4压入栈IL_0002: box [mscorlib]System.Int32 //执行IL box指令,在内存堆中申请System.Int32类型需要的堆空间IL_0007: stloc.0 //弹出堆栈上的变量,将它存储到索引为0的局部变量中IL_0008: ldloc.0//将索引为0的局部变量(即objValue变量)压入栈IL_0009: unbox.any [mscorlib]System.Int32 //执行IL 拆箱指令unbox.any 将引用类型object转换成System.Int32类型IL_000e: stloc.1 //将栈上的数据存储到索引为1的局部变量即value```拆箱操作的执行过程和装箱操作过程正好相反,是将存储在堆上的引用类型值转换为值类型并给值类型变量。C#调用原生代码因为tolua#底层库是使用的tolua(c语言编写),那么就需要通过C#来调用原生代码,我们从LuaDll.cs中摘取一段代码来演示如何从C#中调用原生代码```Public class LuaDll{[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]public static extern void lua_close(IntPtr luaState);}```其中LUADLL对应的字符串就是tolua,在不同的平台上mono会去加载对应的tolua.dll或者tolua.so等文件并调用对应的函数。具体可以参考mono官方的教程。tolua#集成tolua#集成主要分为两部分,一部分是运行时需要的代码包括一些手写的和自动生成的绑定代码,另一部分是编辑器相关代码,主要提供代码生成、编译lua文件等操作,具体就是Unity编辑器中提供的功能。用mono打开整个tolua#的工程,RuntimeSourceGenerate 这个文件里面是生成的绑定代码LuaConst.cs 这个文件是一些lua路径等配置文件。ToLuaBaseLua 一些基础类型的绑定代码Core 提供的一些核心功能,包括封装的LuaFunction LuaTable LuaThread LuaState LuaEvent、调用tolua原生代码等等。Examples 示例Misc 杂项,目前有LuaClient LuaCoroutine(协程) LuaLooper(用于tick) LuaResLoader(用于加载lua文件)Reflection 反射相关EditorEditorCustomCustomSettings.cs 自定义配置文件,用于定义哪些类作为静态类型、哪些类需要导出、哪些附加委托需要导出等。ToLuaEditorExtend 扩展一些类的方法。ToLuaExport.cs 真正生成lua绑定的代码ToLuaMenu.cs Lua菜单上功能对应的代码ToLuaTree.cs 辅助树结构Generate All 流程了解了tolua#的大致文件结构,下面我们来看下tolua#的Generate All 这个功能来分析下它的生成过程。生成绑定代码主要放在ToLuaExport.cs里面,我们并不会对每一个函数进行细致的讲解,如果有什么不了解的地方,可以直接看它的代码。
GenLuaDelegates函数生成委托绑定的代码,它会从CustomSettings.customDelegateList里面取出所有自定义导出的委托列表,然后把CustomSettings.customTypeList里面的所有类型中的委托根据一定规则加入到list中,最后调用ToLuaExport.GenDelegates()方法来生成委托绑定的代码,生成的代码在DelegateFactory.cs文件中。由于该函数比较简单,我们这里不做展开,可以直接查看ToLuaExport.cs中的GenDelegates()并配合DelegateFactory.cs来查看。GenerateClassWraps 函数遍历所有需要导出的类,然后调用ToLuaExport.Generate()方法来生成类的绑定代码。下面我们来看下ToLuaExport.Generate()方法,其基本流程如下所示:
从上面的流程图我们可以看到,整个过程还是比较清楚的,如果这个类是枚举类型,那么它会调用枚举导出的接口,而如果这个类型是一个普通的类,那么它就会调用上图所示的相应的流程将代码导出。至于结构体类型,目前应该是只支持一些特定的结构体,需要在lua中对应一份实现(Assets\ToLua\Lua目录中),当然它生成的代码也有一些依赖于tolua#的核心运行时,我们前面简单的讲解了如何在编辑器中生成绑定代码,接下来我们讲一下它的核心运行时。tolua#的核心运行时tolua#的运行代码包含SourceàGenerate下面的绑定代码以及ToLuaàBaseType代码以及Core下面的核心代码。接下来我们着重讲一下Core下面的几个主要类。LuaAttribute.cs我们前面基础知识部分已经讲过,它在tolua#生成绑定代码时做一些标示使用。LuaBaseRef.csLua中对象对应C#中对象的一个基类,主要作用是有一个reference指向lua里面的对象,引用计数判断两个对象是否相等等。国内的资料不是太多,所以有什么疑问可以去官网或交流群查询。本篇文章使用的UGUI + tolua的 一个组合,Unity版本必须是5.x,因为Unity5对于之前的版本的ab打包策略更改。Tolua的UI架构是使用的puremvc,给我的感觉是把简单的东西所复杂化,但是优点在于把所复杂的逻辑解耦成机械操作,其实对于成熟的项目来说,我还是推荐不要舍弃mvc,当然如果实在不喜,也是可以自己修改,或者写插件便于开发。例子的实现1.先下载LuaFramework UGUI,我们的项目也是从这个项目所修改而来。很多东西别人写过的,我就不直接复制过来,而是给出链接,各位自行去看。2.链接中的目录是ulua的结构目录,其实这是一样的,tolua核心的思想还是和ulua是没差别的。3.找到Examples里面的,main.scene。按照去进行操作,可以实现热更新。在打包的过程中,我们发现生成了StreamingAssets这个文件夹,这是个可读文件夹。在各个平台都有对应的目录,所以之后所有的更新文件都会在这个目录下,而我们所打包的文件也是通过更新StreamingAssets文件去实现更新迭代的。lua源码目录介绍:---3rd:里面是第三方的一些插件lua、实例源码文件,比如:cjson、pbc、pblua、sproto等。---Common:公用的lua文件目录,如define.lua文件,一些变量声明,全局配置等,functions.lua常用函数库,通讯的protocal.lua协议文件。---Controller:控制器目录,它不依赖于某一个Lua面板,它是独立存活在Luavm中的一个操作类,操作数据、控制面板显示而已。---Logic:目录里面存放的是一些管理器类,比如GameManager游戏管理器、NetworkManager网络管理器,如果你有新的管理器可以放到里面。---System:这个目录是cstolua的系统目录,里面存放都是一些常用的lua类,为了优化lua调用速度,用lua重写的unity常用类。---View:这是面板的视图层,里面都是一些被Unity调用的面板的变量,走的是Unity GameObject的生命周期的事件调用。lua和C#的交互两个工具类:LuaHelper.cs静态类//lua调用C#Util.cs //静态方法CallMethod C#调用lua希望大家一起学习一起分享,让lua网络资料更丰富一些!如果有什么理解的不好不到位,求大神指点!下面是我做的几个分析图:
应用部分:1、安装框架
只要在下载LuaFramework,然后用Unity3D打开,这里用的是LuaFramework_UGUI-1.0.4.109版本以及Unity3D 5.2,其他版本理应相似。打开之后需要点击lua菜单里面的Generate All和LuaFramework菜单里Build XXX Resources,以生成一些必要的文件。安装过程可以参见里面的01_uLua_Windows.avi和02_SimpleFramework_UGUI_Windows.avi两个视频(如果在windows系统下)。框架结构请参见,这里不再复述。若运行后能够弹出示范界面,证明安装成功,可以进入下一步。
成功运行示范界面(可要客户端能够运行起来就行)
2、运行Lua代码
这一步的目标很简单,就是让框架运行我们自己写的lua代码,显示一句“helloWorld”。下一步再考虑代码的热更新问题。1)新建场景,并在任意物体中添加Main组件。其实Main组件里面只是调用了AppFacade.Instance.StartUp(),这是框架的起点。框架将会自动完成资源加载、热更新等等事项。
添加Main组件
2)删掉示例的调用。现在不需要框架自带的示例了,需要删掉一些代码,使框架只运行我们编写的lua文件。打开Assets\LuaFramework\Scripts\Manager\GameManager.cs,将OnInitialize修改成下图这个样子。这是lua的入口,框架会调用Main.lua的Main方法。
3)打开Assets\LuaFramework\Lua\main.lua,编写lua代码。这里只添加一句“LuaFramework.Util.Log("HelloWorld");”(如下所示),它的功能相当于Debug.Log("HelloWorld")。
“LuaFramework.Util.Log("HelloWorld")”中的Util是c#里定义的类,供lua中调用。可以打开Assets\LuaFramework\Editor\CustomSettings.cs看到所有可以供lua调用的类,如下图是CustomSettings.cs的部分语句。
CustomSettings.cs的部分语句
再由具体的类可以查找所有的API(参见下面两个图),如下图是Util类的部分语句。
4)运行游戏。点击菜单栏中LuaFramework→Build Windows Resource,生成资源文件。然后运行游戏,即可在控制台中看到打印出的HelloWorld。
生成资源文件
5)调试模式。按照默认的设置,每更改一次lua代码,都需要执行Build XXX Resource才能生效。读者可以将Assets\LuaFramework\Scripts\ConstDefine\AppConst.cs中的LuaBundleMode修改为false,这样代码文件便不会以AssetBundle模式读取,会直接生效,以方便调试。
设置LuaBundleMode
3、代码热更新
热更新的原理接下来便要尝试代码热更新,让程序下载服务器上的lua文件,然后运行它。在说明热更新之前,需要先看看Unity3D热更新的一般方法。如下图所示,Unity3D的热更新会涉及3个目录。
热更新的过程
游戏资源目录:里面包含Unity3D工程中StreamingAssets文件夹下的文件。安装游戏之后,这些文件将会被一字不差地复制到目标机器上的特定文件夹里,不同平台的文件夹不同,如下所示(上图以windows平台为例)
数据目录:由于“游戏资源目录”在Android和IOS上是只读的,不能把网上的下载的资源放到里面,所以需要建立一个“数据目录”,该目录可读可写。第一次开启游戏后,程序将“游戏资源目录”的内容复制到“数据目录中”(步骤1,这个步骤只会执行一次,下次再打开游戏就不复制了)。游戏过程中的资源加载,都是从“数据目录”中获取、解包(步骤3)。不同平台下,“数据目录”的地址也不同,LuaFramework的定义如下:
网络资源地址:存放游戏资源的网址,游戏开启后,程序会从网络资源地址下载一些更新的文件到数据目录。这些目录包含着不同版本的资源文件,以及用于版本控制的files.txt。Files.txt的内容如下图所示,里面存放着资源文件的名称和md5码。程序会先下载“网络资源地址”上的files.txt,然后与“数据目录”中文件的md5码做比较,更新有变化的文件(步骤2)。
LuaFramework的热更新代码定义在Assets\LuaFramework\Scripts\Manager\GameManager.cs,真正用到项目时可能还需少许改动。开始热更新代码吧!那么开始测试热更新代码的功能吧!热更上述实现的“HelloWorld”。1)修改配置。框架的默认配置是从本地加载文件,需要打开AppConst.cs将UpdateMode设置为true(才会执行步骤2),将LuaBundleMode设置为true,将WebUrl设置成服务器地址。如下图所示。
AppConst的配置
2)配置“网络资源”。笔者使用iis开启本地服务器,然后将StreamingAssets里面的所有内容复制到服务器上面。必要时要配置一些权限,让所有文件都都可以下载3)测试热更。改一下Lua脚本(如将HelloWorld改为Hello Lpy2),点击Build Windows Resource,将“工程目录/StreamingAssets”里面的文件复制到服务器上。再将脚本改成其他内容,然后Build Windows Resource,覆盖掉本地资源。运行游戏,如果程序显示“Hello Lpy2”的代码,证明成功从网上拉取了文件。
代码热更新
附录:一、语法:
局部变量声明:用local声明 相当于javascript var声明类: classA={}int类型转换成string:tostring(i);字符串相加+用“..”: "A".."B"="AB"属性获取用. 调用方法用:
A:a();if条件语句: if a==0 then
print('干啥') endif..else条件控制:if 条件 then … elseif 条件 then … else … end注意:lua 中没有 switch case 语句1.应用类库using UnityEngine:luanet.load_assembly('UnityEngine')2.lua全局使用C# Coment ,define.lua声明后其他lua脚本直接使用:GameObject=UnityEngine.GameObjectParticleSystem=UnityEngine.ParticleSystem3.添加脚本:newGameObj:AddComponent(luanet.ctype(ParticleSystem))4.场景新建一个GameObject: local newGameObj=GameObject('NewObj')5.Unity对象转lua对象:local= newObject(obj);6.C#获得Lua函数LuaFunction f=l.GetFunction("函数名");f.Call(参数)调用7.lua协程开启:coroutine.start(方法名);等待:coroutine.wait(时间s);8.根据transform查找子对象:local label = go.transform:FindChild('##/Text');9.获取脚本:transform:GetComponent('LuaBehaviour');10.输出信息:logWarn("OnDestroy----&&&");log(go.name);一、tolua#c#调用lua:LuaState[变量名/函数名]1.LuaStatea.执行lua代码段DoString(string)DoFile(.lua文件名)Require(.lua文件名(但没有.lua后缀))b.获取lua函数或者表LuaFunction func = lua.GetFunction(函数名);
LuaFunction func = lua[函数名] as LuaFLuaTable table = lua.GetTable(表名);c.Start():如果需要使用wrap,则需要调用该方法2.LuaFunctionCall()3.LuaTableLuaTable[变量名/函数名]ToArray()lua调用c#在c#中将引用传递到lua中后:1.通过“.” (点号)来使用非静态的变量以及静态的变量与方法2.通过'':“ (冒号)来使用非静态的方法3.通过"{}"来传递数组给c#4.创建GameObject:newObject(变量)5.摧毁GameObject:destroy(变量)6.获取组件:GetComponent('LuaBehaviour')二、LuaFramework(使用PureMVC)
a.基础模块1.Util:对Mono的功能进行封装,这样不继承Mono的类就能使用Mono的东西了(如transform.Find、GetComponent);还有其他的工具方法2.AppFacade:继承Facade,整套框架的入口3.Base:继承MonoBehaviour,是一切View和Manager的基类;持有各种Manager的引用;能注册移除(view所感兴趣的)信息4.View:只有一个方法:public virtual void OnMessage(IMessage message) 这是处理信息的方法5.Manager:继承Base6.AppView:继承View,是一个范例:注册View所感兴趣的信息,处理信息b.lua模块1.LuaFileUtils:通过.lua文件路径和AssetBundle文件路径这两种方式来找.lua文件,并读取返回byte[]2.LuaLoader:继承LuaFileUtils,并无重要变化3.LuaEvent:类似c#中的event,提供Add和Remove方法4.LuaLooper:继承MonoBehaviour,在Update / LateUpdate / FixedUpdate中执行对应的LuaEvent5.LuaBinder:如果执行的.lua文件需要用到unity中的类型,则需要用这个类给LuaState进行绑定6.LuaManager:继承Manager,入口类,初始化Lua代码加载路径(调试模式下是在Assets \ LuaFramework目录下,非调试模式是在C:\luaframework\lua(window系统),默认是非调试模式),引用一个LuaState并封装其功能(读取lua文件、调用方法等)7.LuaBehaviour:继承View,在Awake / Start中调用lua中对应的方法;并提供点击事件的相关处理c.Manager模块1.ResourceManager:加载AssetBundle的相关操作。在pc平台上默认加载的是Assets\StreamingAssets里的东西,移动平台上则是Application.persistentDataPath。那么如果我们想在pc平台上像移动平台一样读取外部路径(使用www),在pc平台模拟热更新,那么就可以在Initialize这个方法修改:m_BaseDownloadingURL = "file:///" + Util.DataP例子1展示了最小的tolua#环境,以及执行一段lua代码操作代码如下:```LuaStatelua=newLuaState();lua.Start();stringhello=
@"print('hello tolua#')";lua.DoString(hello, "HelloWorld.cs");lua.CheckTop();lua.Dispose();lua=```LuaState封装了对lua 主要数据结构 lua_State 指针的各种堆栈操作。一般对于客户端,推荐只创建一个LuaState对象。如果要使用多State需要在Unity中设置全局宏 MULTI_STATELuaState.Start 需要在tolua代码加载到内存后调用。如果使用assetbunblde加载lua文件,调用Start()之前assetbundle必须加载好LuaState.DoString 执行一段lua代码,除了例子,比较少用这种方式加载代码,无法避免代码重复加载覆盖等,需调用者自己保证。第二个参数用于调试信息,或者error消息(用于提示出错代码所在文件名称)LuaState.CheckTop 检查是否堆栈是否平衡,一般放于update中,c#中任何使用lua堆栈操作,都需要调用者自己平衡堆栈(参考LuaFunction以及LuaTable代码), 当CheckTop出现警告时其实早已经离开了堆栈操作范围,这是需自行review代码。LuaState.Dispose 释放LuaState 以及其资源。注意:此例子无法发布到手机展示了dofile跟require的区别, 代码如下:```LuaStatelua=voidStart()
lua =newLuaState();
lua.Start();//如果移动了ToLua目录,需要自己手动,这里只是例子就不做配置了stringfullPath= Application.dataPath +"/ToLua/Examples/02_ScriptsFromFile";
lua.AddSearchPath(fullPath);
}voidOnGUI()
{if(GUI.Button(newRect(50,50,120,45),"DoFile"))
lua.DoFile("ScriptsFromFile.lua");
}elseif(GUI.Button(newRect(50,150,120,45),"Require"))
lua.Require("ScriptsFromFile");
lua.Collect();
lua.CheckTop();
}voidOnApplicationQuit()
lua.Dispose();
}```tolua#DoFile函数,跟lua保持一致行为,能多次执行一个文件。tolua#加入了新的Require函数,无论c#和lua谁先require一个lua文件, 都能保证加载唯一性LuaState.AddSearchPath 增加搜索目录, 这样DoFile跟Require函数可以只用文件名,无需写全路径LuaState.DoFile 加载一个lua文件, 注意dofile需要扩展名, 可反复执行, 后面的变量会覆盖之前的DoFile加载的变量LuaState.Require 同lua require(modname)操作, 加载指定模块并且把结果写入到package.loaded中,如果modname存在, 则直接返回package.loaded[modname]LuaState.Collect 垃圾回收, 对于被自动gc的LuaFunction, LuaTable, 以及委托减掉的LuaFunction, 延迟删除的Object之类。等等需要延迟处理的回收, 都在这里自动执行注意:虽然有文件加载,但此例子无法发布到手机, 如果ToLua目录不在/Assets目录下, 需要修改代码中的目录位置展示了如何调用lua的函数, 主要代码如下:```privatestringscript=
@"function luaFunc(num)return num + 1endtest = {}test.luaFunc = luaFunc";LuaFunctionluaFunc=LuaStatelua=voidStart()
{newLuaResLoader();
lua =newLuaState();
lua.Start();
DelegateFactory.Init();
lua.DoString(script);//Get the function objectluaFunc = lua.GetFunction("test.luaFunc");if(func !=null)
{intnum= luaFunc.Invoke(123456);
Debugger.Log("generic call return: {0}", num);
num = CallFunc();
Debugger.Log("expansion call return: {0}", num);
FuncFunc= luaFunc.ToDelegate&();
num = Func(123456);
Debugger.Log("Delegate call return: {0}", num);
num = lua.Invoke("test.luaFunc",123456,true);
Debugger.Log("luastate call return: {0}", num);
lua.CheckTop();}voidOnDestroy()
{if(luaFunc !=null)
luaFunc.Dispose();
lua.Dispose();
}intCallFunc()
luaFunc.BeginPCall();
luaFunc.Push(123456);
luaFunc.PCall();intnum= (int)luaFunc.CheckNumber();
luaFunc.EndPCall();
}```tolua# 简化了lua函数的操作,通过LuaFunction封装(并缓存)一个lua函数,并提供各种操作, 建议频繁调用函数使用无GC方式。LuaState.GetLuaFunction 获取并缓存一个lua函数, 此函数支持串式操作, 如"test.luaFunc"代表test表中的luaFunc函数。LuaState.Invoke 临时调用一个lua function并返回一个值,这个操作并不缓存lua function,适合频率非常低的函数调用。LuaFunction.Call() 不需要返回值的函数调用操作LuaFunction.Invoke() 有一个返回值的函数调用操作LuaFunction.BeginPCall() 开始函数调用LuaFunction.Push() 压入函数调用需要的参数,通过众多的重载函数来解决参数转换gc问题LuaFunction.PCall() 调用lua函数LuaFunction.CheckNumber() 提取函数返回值, 并检查返回值为lua number类型LuaFunction.EndPCall() 结束lua函数调用, 清楚函数调用造成的堆栈变化LuaFunction.Dispose() 释放LuaFunction, 递减引用计数,如果引用计数为0, 则从_R表删除该函数注意:无论Call还是PCall只相当于lua中的函数'.'调用。请注意':'这种语法糖 self:call(...) == self.call(self, ...)c# 中需要按后面方式调用, 即必须主动传入第一个参数self展示了如何访问lua中变量,table的操作```privatestringscript=
@"print('Objs2Spawn is: '..Objs2Spawn)var2read = 42varTable = {1,2,3,4,5}varTable.default = 1varTable.map = {}varTable.map.name = 'map'meta = {name = 'meta'}setmetatable(varTable, meta)function TestFunc(strs)print('get func by variable')end";voidStart(){newLuaResLoader();LuaStatelua=newLuaState();
lua.Start();
lua["Objs2Spawn"] =5;
lua.DoString(script);//通过LuaState访问Debugger.Log("Read var from lua: {0}", lua["var2read"]);
Debugger.Log("Read table var from lua: {0}", lua["varTable.default"]);//LuaState 拆串式tableLuaFunctionfunc= lua["TestFunc"]asLuaF
func.Call();
func.Dispose();//cache成LuaTable进行访问LuaTabletable= lua.GetTable("varTable");
Debugger.Log("Read varTable from lua, default: {0} name: {1}", table["default"], table["map.name"]);
table["map.name"] ="new";//table 字符串只能是keyDebugger.Log("Modify varTable name: {0}", table["map.name"]);
table.AddTable("newmap");LuaTabletable1= (LuaTable)table["newmap"];
table1["name"] ="table1";
Debugger.Log("varTable.newmap name: {0}", table1["name"]);
table1.Dispose();
table1 = table.GetMetaTable();if(table1 !=null)
Debugger.Log("varTable metatable name: {0}", table1["name"]);
}object[]list= table.ToArray();for(inti=0; i & list.L i++)
Debugger.Log("varTable[{0}], is {1}", i, list[i]);
table.Dispose();
lua.CheckTop();
lua.Dispose();
}```luaState["Objs2Spawn"] LuaState通过重载this操作符,访问lua _G表中的变量Objs2SpawnLuaState.GetTable 从lua中获取一个lua table, 可以串式访问比如lua.GetTable("varTable.map.name") 等于 varTable-&map-&nameLuaTable 支持this操作符,但此this不支持串式访问。比如table["map.name"] "map.name" 只是一个key,不是table-&map-&nameLuaTable.GetMetaTable() 可以获取当前table的metatableLuaTable.ToArray() 获取数组表中的所有对象存入到object[]表中LuaTable.AddTable(name) 在当前的table表中添加一个名字为name的表LuaTable.GetTable(key) 获取t[key]值到c#, 类似于 lua_gettableLuaTable.SetTable(key, value) 等价于t[k] = v的操作, 类似于lua_settableLuaTable.RawGet(key) 获取t[key]值到c#, 类似于 lua_rawgetLuaTable.RawSet(key, value) 等价于t[k] = v的操作, 类似于lua_rawset展示了如何使用lua协同, lua 代码如下:```functionfib(n)locala, b=0,1whilen&0doa, b=b, a+b
n=n-1endreturnaendfunctionCoFunc()print('Coroutine started')fori=1,10,1doprint(fib(i))
coroutine.wait(0.1)endprint("current frameCount:"..Time.frameCount)
coroutine.step()print("yield frameCount:"..Time.frameCount)localwww=UnityEngine.WWW("http://www.baidu.com")
coroutine.www(www)locals=tolua.tolstring(www.bytes)print(s:sub(1,128))print('Coroutine ended')endfunctionTestCortinue()
coroutine.start(CoFunc)endlocalcoDelay=nilfunctionDelay()localc=1whiletruedocoroutine.wait(1)print("Count:"..c)
c=c+1endendfunctionStartDelay()
coDelay=coroutine.start(Delay)endfunctionStopDelay()
coroutine.stop(coDelay)end```c#代码如下:```newLuaResLoader();lua= newLuaState();lua.Start();LuaBinder.Bind(lua);DelegateFactory.Init();looper= gameObject.AddComponent();looper.luaState=lua.DoString(luaFile.text, "TestLuaCoroutine.lua");LuaFunctionf=lua.GetFunction("TestCortinue");f.Call();f.Dispose();f=```必须启动LuaLooper驱动协同,这里将一个lua的半双工协同装换为类似unity的全双工协同fib函数负责计算一个斐那波契ncoroutine.start 启动一个lua协同coroutine.wait 协同中等待一段时间,单位:秒coroutine.step 协同中等待一帧.coroutine.www 等待一个WWW完成.tolua.tolstring 转换byte数组为lua字符串缓冲coroutine.stop 停止一个正在lua将要执行的协同总结
1.对于一个panel,需要添加或修改的文件:a.添加xxxPanel & xxxCtrlb.修改define、Game、CtrlManager详细的可见:http://blog.csdn/adambieber/article/details/2.在lua中使用AB包内的资源的两种方法:a.panelMgr:CreatePanel('Prompt', this.OnCreate);b.resMgr:LoadPrefab('prompt', { 'PromptItem' }, this.InitPanel);其中a是对b的进一步封装,因此两者都需要提供AB包名、要访问的包内资源名字(如果是panel,则默认资源名为AB包名+"Panel")以及回调方法(参数是AB包中的资源)3.热更新的四个步骤:打包、解包、更新和加载。而这四个步骤框架已经给我们封装好了,基本上就不需要我们去管了,但还是很有必要理解其中的过程。a.打包:将资源全部打包到StreamingAssets文件夹打包类:LuaFramework / Editor / Packager打包lua文件:HandleLuaBundle,对Assets\LuaFramework\Lua 与 Assets\LuaFramework\ToLua\Lua这两个目录下的所有lua文件进行打包打包图片等资源:HandleExampleBundleb.解包:在移动端StreamingAssets这个文件夹是只读的,但是要做热跟新的话,就需要写入文件,因此Application.persistentDataPath这个可读可写的路径才是数据在移动端的存放路径,同时也为了比较MD5的值,就需要将StreamingAssets的东西解包(复制)到Application.persistentDataPathc.更新:files.txt这个文件记录了所有的资源文件及其MD5值,每次进入游戏时都会从服务器下载最新的files.txt,然后对其遍历比较MD5值,如果值不同或者不存在则下载d.加载:先加载资源的依赖,再加载资源那么,如果我们对外发布了一个版本1.1,然后更改资源,发布1.2,要做的就是:重新生成apk并上传,然后将StreamingAssets文件夹下的东西上传到服务器,具体位置见AppConst.WebUrl;对于用户来说,如果他安装的是1.1,那么就会下载更新,如果他安装的是1.2,那么解包之后就得到最新的资源了,无需更新了。4.整套框架的工作流程:c#打包好后,启动游戏,GameManager会进行一些判断,如果这是游戏安装之后的第一次启动,那么就会进行解包操作。如果AppConst.UpdateMode为false,那么就不会检测更新,否则就会进行更新操作。然后进入初始化操作,调用Game.lua中的OnInitOK方法,进入lua逻辑。lua然后调用指定控制器的Awake方法、PanelManager的CreatePanel方法,调用c#代码,创建panel,为其添加LuaBehaviour,调用xxxPanel.lua的方法,获取控件引用,进行逻辑处理。外部学习链接:1.2.3.
?开启? 【iAPP实现进入界面执行逐一显】 〖 15:22:14〗 《//首先开一个线程,因为你有这么多的stop要执行,其次必须使用ufusui(),否则可能不会显示你的字体。切记:文字必须设置“text=”,否则很尴尬,还有我这里的8,14是两个文...
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua 是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeir...
1.1程序块:Lua执行的每段代码,例如一个源代码文件或者交互模式中输入的一行代码,都称为一个程序块 1.2注释:- -
--]] 1.3全局变量:无需声明,只需将值赋予一个全局变量就可以创建了。无需删除,若要删除直接赋值nil。 1.4解释器程序选项...
Nginx API for Lua Introduction ngx.arg ngx.var.VARIABLE Core constants HTTP method constants HTTP status constants Nginx log level consta...
指令集 lua_capture_error_log lua_use_default_type lua_malloc_trim lua_code_cache lua_regex_cache_max_entries lua_regex_match_limit lua_packa...
文丨郭嘉掉线了 名剑俱坏,英雄安在繁华几时相交代?想兴衰,苦为怀;东家方起西家败,世态有如云变改。成,也是天地哀;败,也是天地哀。 金铁修、赋笔秋,欲成侠骨需求剑,不是痴狂肯着书。一步重、一步缓、一步权名,一步平淡。 惊 梦 星月在天,武林行地,透过密匝的残林掩映着的余辉冲...
DaoCloud已经提示了如何配置如下图: 选择Preferences 阿里云配置流程一样,地址在下图的位置可以找到: ?偷懒了。
青春里装成熟的小孩 如果你的宿舍里有一个和你身材相似的兄弟,那么你一定要珍惜,因为你们可以互穿衣服,可以一起讨论女朋友的身高,那是可遇不可求的一种缘分 1 老干身高186,长的清秀,笑起来你都看不到他的眼睛。其实老干并不姓干,而且他的名字和干旱一点关系都没有,反而是命中有水...
视觉明月升起。天幕上,夜空与黄昏各自占据了一半,缩在地平线两端的太阳与月亮就仿佛两个胆小的将军,互相号令着自己领域内的光芒冲向对方的阵地,随后消散在虚无之中。——本该是这样的,但今天似乎不太一样。两枚天体都散发出了比以往强烈许多倍的光亮,我不得不在眼前举起一片附有魔法的玻璃...
上周四晚上11点过孩子从学校打来电话,两件事情:1、和同学打篮球不小心打坏了同学的眼镜要赔偿100元;2、询问他现在用的耳机多少钱,同学要买。想了解更多的信息孩子也不愿意说,心中泛起不良的情绪和担忧。会不会是和同学打架互相把耳机和眼镜摔坏了?相互进行赔偿?心中顿时充满不安,...

我要回帖

更多关于 unity3d 触碰逻辑 的文章

 

随机推荐