unity3d热更新插件uLua学习整理

前言

IOS不能热更新,不是因为不能用反射,是因为
System.Reflection.Assembly.Load 无法使用
System.Reflection.Emit 无法使用
System.CodeDom.Compiler 无法使用
这三个不能用,就把传统dotnet动态路径坑死了
为啥“这三个不能用,就把传统dotnet动态路径坑死了”呢
动态载入dll或者cs的方法就这几个, IOS 下不能动态载入dll或者cs 文件,已经编译进去的没事
=========================================================

尽量只把U3D当一个渲染引擎来看待, 不然你会发现热更资源很悲剧, 资源一定要与逻辑分开, 因为U3D用的是类的序列化, 后期改动会导致前面导出的资源不能用。就和开发AS3游戏差不多了。可以这么理解
1.prefab尽量不去绑定脚本,尽量在代码里AddComponent<接口实现脚本>,在实例prefab的GetComponent<接口脚本>.接口操作。
2.prefab可以绑定那些不会再改动的脚本。
============================================================

插件下载地址:

http://ulua.org/

?toLua下载地址:

https://github.com/topameng/CsToLua

阿萌对ULUA1.03的BUG修改文章:

http://user.qzone.qq.com/5281069/blog/1408526450?ptlang=2052&ADUIN=522414019&ADSESSION=1425950543&ADTAG=CLIENT.QQ.5396_.0&ADPUBNO=26442

?蛮牛上找的关于ULUA的文章:

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

http://www.unitymanual.com/blog-27966-2568.html?_dsign=0c1fb317

==============写LUA相关的工具?==============

BabeLua-vs2012-and-vs2013插件:

设置参考http://www.cocoachina.com/bbs/read.php?tid=205043

使用技巧http://blog.csdn.net/babestudio

LuaStudio,请使用Administrator管理员权限,否则会挂死!!!?

?

==============uLua插件导入到unity3d常见问题?==============?

导入uLua插件运行自带的例子报错问题:DllNotFoundException: 这个在其老外写的README里已经说了如何解决。

(1)将plugins目录放到最外面,重启unity。

(2)真机没有打包libulua.so进包导致,或者模拟器也有些设置不对。打包的时候把libulua.so打包进libs\armeabi-v7a

?

EntryPointNotFoundException: 解决方案:

EntryPointNotFoundException:这个类型错误不太单一,可选择下面2中方法解决:(方案1)把除了Assets跟 ProjectSettings目录之外的都删除掉,重新打开工程。(方案2)如果在MAC上,选择IOS平台,很容易出现,切换到MAC/PC平台基本 上就解决了,你不能要求在MAC下一定要运行IOS的动态库。

0.16框架报错解决办法:

0.16框架基于u3d4.6,所以在老版本的u3d打开会报错,如果是老版本的话把LuaWrap除了Base目录外所有的Wrap cs文件删掉,然后lua clear菜单调用下就好了。

?attempt to index global ‘UnityEngine‘:

uaScriptException: [string "define.lua"]:1: attempt to index global ‘UnityEngine‘ (a nil value)解决:生成wrap文件。

tolua c#简单使用方法

打开Editor/BindLua.cs文件,在static BindType[] binds = new BindType[]变量末尾一行加入要导入的cs类,比如Resources类,保存等u3d编译完后,选择“Lua/Gen LuaBinding Files”编译即可,以后就可以在lua里面使用此类了,而不要导入进来。映射public成员

?C#里面有个编辑器工具类可以用Wrap映射到lua里使用
public static class LuaBinder {
    public static void Bind(IntPtr L) {
        ObjectWrap.Register(L);
    }
}

这个等价于我们之前在lua中写的
luanet.import_type("UnityEngine.Object")

lua脚本里在定义基础类型的时候
Object = luanet.import_type("UnityEngine.Object")
Object = UnityEngine.Object
这两种写法有区别吗,还是随便写哪个都行?
用后者 效率高。前者是反射

_lua_tocbuff 是阿萌自己添加的,用于xml
_luaopen_ffi 是luajit的,
_luaopen_luaXML
删掉函数声明即可

lua的loop库可以正常用在ulua里吗
看库是否用到了c++代码了

自己直接拿lua5.1源码编的ulua.dll
Windows下用可以用vs编吧,我把那个lua_wrap.c也添加了
如果你的错误是找不到入口,就加这个宏,LUA_BUILD_AS_DLL,具体查一下readme。

加上这个_GT(typeof(JsonObject)), 点击GEN LUA WRAPPER后unity直接就崩溃了

记得嵌套2层以上的模板就不行了,如 Dictionary>

最后发布程序的时候,会包很多错,是由于TOLUA无法识别代码中加了编辑器运行的条件编译判断,所以手动注释掉与这相关的代码不报错就好,就能正常编译打包程序了。

如何在LUA中遍历CSharp的数组

    LuaTable mMap;

    Dictionary mLuaMap;

    public LuaTable Map {

        get {

            if (mMap == null) {

                mLuaMap = new Dictionary( );

                mMap = TTLuaMain.Instance.luaState.NewTable( );

                for (int i = 0, iMax = mVariables.Length; i < iMax; i++) {

                    var val = mVariables[i];

                    mMap[val.name] = val.val;

                    mLuaMap.Add(val.name, val);

                }

            }

            return mMap;

        }

} 

LuaVariable 是我自定义的类型,你可以随便传, 这个是指我在C#里写的数组类型

核心思想就是把你C#数组里面的东西,放入table,如果是单纯的数据类型,你可以直接lua里面for 0,maxlength  如果是字典类型的,你就要转换。

比如我这里:

通过TOLUA,把Collider2d类型注册给ULUA,直接lua里面for 0,maxlength 遍历。

再贴上ULUA群主写的范例:

在lua里怎么遍历 C#的object数组:


通过 IEnumerator:

uLua自带的案例

2015年3月26日 15:58:22 补充说明,升级到U3D5.0.0F4,U3D API改了很多,都得用getcomponent函数,以前直接THIS.transform已经不能用了,所以自带的小案例会报错。

02_CreateGameObject?:

这里我先写个最平常不过的U3D下的C#脚本?

=======================ExtendMonoScript?.cs================

public class ExtendMonoScript : MonoBehaviour {

    void Start ( ) {     

  aaa( );  

}   

public void aaa ( ) { 

      Debug.Log(this + "普通的函数调用!"); 

  }

   public static void StaticMethod ( ) {

       Debug.Log("公有静态函数!!");

   } 

  private static void PirvateStaticMethod ( ) {  

     Debug.Log("私有静态函数!!");

   }   

public  void ObjMethod ( ) {   

    Debug.Log("公有成员函数!!");

   }  

private void PrivateObjMethod ( ) {   

    Debug.Log("私有成员函数!!"); 

  }

}

=======================ExtendMonoScript?.cs================

=======================CreateGameObject.cs===============

using UnityEngine;
using System.Collections;
// lua
using LuaInterface;

public class CreateGameObject : MonoBehaviour {

    private string script = @"
            luanet.load_assembly(‘UnityEngine‘)
            GameObject = luanet.import_type(‘UnityEngine.GameObject‘)
            luanet.load_assembly(‘Assembly-CSharp‘)

            local newGameObj = GameObject(‘Creat_GameObj_In_Lua‘)
            newGameObj:AddComponent(‘ExtendMonoScript‘)
        ";

    void Start () {
        LuaState l = new LuaState();
        l.DoString(script);
    }
}
=======================CreateGameObject.cs===============

load_assembly加载程序集,这样LUA才能使用其API

import_type导入类型,这样LUA才能使用改类型

newGameObj:AddComponent(‘ExtendMonoScript‘)这里注意初学LUA,“:”与“.”的区别

DoString(script);真正使用ULUA插件时不要用这个,因为效率低下。

03_AccessingLuaVariables:

========================AccessingLuaVariables.cs==========================

using UnityEngine;
using System.Collections;
using LuaInterface;

public class AccessingLuaVariables : MonoBehaviour {

    // 对象调用函数用:     load_assembly是载入程序集     import_type是引入类型
    // ..相当于是C#里的字符串+,就是连接字符串的意思
    // local表示局部变量,没写都为全局变量
    // {}表示TABLE,lua里数组,链表等等结构都使用该方式模拟出来
    // table.insert表示Append,在数组最后插入一个新元素
    private string script = @"
            luanet.load_assembly(‘UnityEngine‘)
            GameObject = luanet.import_type(‘UnityEngine.GameObject‘)

            g_particles = {}

            for i = 1, g_Objs2Spawn, 1 do
                local newGameObj = GameObject(‘NewObj‘ .. tostring(i))
                local ps = newGameObj:AddComponent(‘ParticleSystem‘)
                ps:Stop()

                table.insert(g_particles, ps)
            end

            g_var2read = 42

            g_array = {}
            for i = 1, 5, 1 do
                table.insert(g_array, i)
            end
        ";

    void Start () {
        LuaState l = new LuaState();
        // 给全局变量赋值
        l["g_Objs2Spawn"] = 5;
        l.DoString(script);

        // 取得全局变量
        print("Read from lua: " + l["g_var2read"].ToString());

        // Get the lua table as LuaTable object
        LuaTable particles = (LuaTable)l["g_particles"];

        // Typical foreach over values in table
        foreach( ParticleSystem ps in particles.Values )
        {
            ps.Play();
        }

        l["g_var2read"] = 48;
        Debug.Log("Read from lua: " + l["g_var2read"].ToString( ));
        // Lua里数值都是当的double,动态类型,不需要强制类型转换
        //float akb = (float)l["var2read"];   // error
        //int akb = (int)l["var2read"];   // error
        double akb = (double)l["g_var2read"];   // ok
        Debug.Log(akb);
        l["g_var2read"] = "AKB48";    // ok
        Debug.Log("Read from lua,赋值字符串后: " + l["g_var2read"].ToString( ));
        string str = (string)l["g_var2read"];     // ok
        Debug.Log("str = " + str);

        LuaTable nums = (LuaTable)l["g_array"];
        foreach ( double num in nums.Values ) {
            Debug.Log("num = " + num);
        }
        foreach ( double key in nums.Keys ) {
            Debug.Log("关键字 = " + key);
        }
        //Debug.Log("nums[1] = " + nums["1"].ToString());   // error
    }
}
========================AccessingLuaVariables.cs==========================

群共享的小框架SimpleFramework

baseLua=桥 ,继承baselua的c#类一般不需要导出wrap。

V0.2.0发布EXE调整:

首先直接发布EXE报错:

修改打包编辑器脚本:

直接简单的把打包目标改成WIN,重新打包。

载入AB的资源管理脚本:


可以看到这里对路径只写了安卓和IOS平台的判断,再就是是否是调试版的判断。改完后,按GUI的提示改下常量为DEBUG模式,以拿到路径。这样发布EXE就正常了。

=================启动SimpleFramework_v0.1.5的服务端问题======================

启动 SimpleFramework_v0.1.5的服务端这个是什么问题

2014-10-12 10:46:48,573 [7128] ERROR DefaultBootstrap - Failed to create server instance ManagementServer!

System.Reflection.TargetInvocationException: 调用的目标发生了异常。 ---> System.TypeInitializationException: “SuperSocket.ServerManager.ManagementServer”的类型初始值设定项引发异常。 ---> System.IO.FileNotFoundException: 未能加载文件或程序集“Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed”或它的某一个依赖项。系统找不到指定的文件。

安装。net 4,没有找到json的dll ,已经在目录里面有了,跟exe同目录

把这个,Newtonsoft.Json.dll考到 debug执行文件 同目录就可以了。

==============================================================================

TOLUA,封装C#与LUA通信原理:

LuaDLL.lua_pushstdcallcfunction(L, IndexArray);
        LuaDLL.lua_rawset(L, -3);
        LuaDLL.lua_pushstring(L, "__gc");
        LuaDLL.lua_pushstdcallcfunction(L, __gc);
        LuaDLL.lua_rawset(L, -3);

pushstring是把toluaindex压栈,dostring我记得是执行这段字符串,生成闭包,最后是以toluaindex为key.闭包为value存放在注册表,这样可以不被lua直接访问到,如果我记得不错的话,rawset是绕过元表直接设置table,index表示的是lua堆栈中对象的索引位置。

怎么知道index是多少呢?如这个里面的-3


-3是luanet array,就是个栈,而且第一个-3和第二个是不一样的,理解栈,压栈,出栈就好了,前面四句就是luanetarray[_index]=函数,settop是设置栈顶,这里为0是清空栈。

最后的-3是不是倒数第3次的push。lua_pushstdcallcfunction(L, IndexArray); 是这行的IndexArray吗?

非也,是那个元表,rawset只是把key 和value弹出而已,元表留在栈顶,实际上这次是给这个元表加一个key为_gc,value为gc函数的键值。

=====================================

me for nlua小框架:

使用步骤:

//附带地鼠资源打包教程和编辑脚本测试工程教程:
1.执行编辑器菜单 ME tools/清理缓存,让一切重新开始。
2.执行编辑器菜单 ME tools/把Atlas目录下的.png图片作为图集资源并放入Data目录。
3.在Project窗体内 鼠标点选选中 Assets/Builds/GUI,然后 执行编辑器菜单 ME tools/独立打包选中目录下的各个对象并放入Data目录。
4.执行编辑器菜单 ME tools/制作更新包:把Data目录压缩为一个zip包并放入StreamingAssets目录。
通过以上步骤完成资源和升级包的制作了。
如果在编辑器进行代码修改或者资源修改,请重复以上步骤。
如果仅仅修改 Assets/Data/lua 下的逻辑脚本,您只需要执行以上的1和4步骤

me for nlua 把plugins下面的x86和x86_64两个文件夹删除掉,就能发布android了。

me for nlua编译选项推荐使用
UNITY_3D;USE_KERALUA;LUA_CORE;CATCH_EXCEPTIONS
即使用c版lua加速,也可解决打印(Debug.Log)中文日志显示乱码问题。

参考一下ME 游戏框架,全局就一个luastate,
ME框架的思路就是 一个GameObject 对应挂个LuaBehaviour.cs脚本,这个LuaBehaviour.cs脚本DoFile一个
lua脚本,lua脚本和LuaBehaviour.cs交互控制。全局就有一个luastate,每个脚本其实就是一个table。

============================================================
U3D5的更新:

各位使用MAC + U5 64的同学,如果遇到编辑器环境下luastate == null的情况,请下载我上传群共享的
libulua.zip替换其底层库,可暂时绕过此问题,将来有时间研究下。

时间: 2024-11-11 22:06:10

unity3d热更新插件uLua学习整理的相关文章

Unity3D热更新之LuaFramework篇[02]--用Lua创建自己的面板

在上篇文章 Unity3D热更新之LuaFramework篇[01]--从零开始 中,我们了解了怎么获得一个可用的LuaFramework框架. 本篇将我会先介绍一下如何配置Lua开发环境,然后分析在此框架中加载面板的流程,以及如何创建自己的面板. 1.配置Lua开发环境 有一点要说明的是,使用此种方式(ToLua+LuaFramework)做热更新,则意味着你的大部分逻辑都需要改用Lua语言来编写. 因此,开发前得先得配置好Lua开发环境.毕竟,工欲善其事,必先利其器. 环境配置大概分以下三个

Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween

在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此事.本篇文章就来继续这个工作. 从Lua中调用C#代码 1.创建UI监听脚本 打开之前的工程,在Assets/LuaFrameworks/Scripts/Common下,创建一个UIEventEx.cs脚本,将LuaBehaviour.cs中的AddButtonClick以及AddInputFiel

Unity3D热更新全书-PageZero

由于深刻的认识到自己是个思维跳跃的人,深入浅出是个我还要努力很久的目标,为了让大家不至于在我乱七八糟的文字中迷失,特整理目录一份 无分类 <Unity3D热更新全书-何谓热更新,为何热更新,如何热更新> 这一篇是写给对热更新完全没概念的人 下载系列 还没写 加载系列 <Unity3d热更新全书-资源加载(一)从AssetBundle说起 > 这一篇是探讨使用AssetBundle来做资源更新的问题,希望能让更多人理解AssetBundle是有害的 脚本系列 <Unity3D热

Unity3D热更新全书FAQ

只要有程序员朋友们问过两次的问题 就会收录在此FAQ中 1.C#Light对比LUA有什么好处 C#Light是静态类型脚本语言,语法同C#,Lua是动态类型脚本语言,这两种都有人喜欢. 我更喜欢静态类型,于是有了C#Light 2.C#Light性能怎么样 C#Light和Unilua 和ulua都做过简单性能测试,比Unilua快,和ulua各有胜负 3.C#Light IOS可以使用么 完全可以,均妥善测试 4.为什么C#Light例子和NGUI一起用会编译不过 因为Unity没有库的概念

Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法

时隔一个多月我又回来啦! 坚持真的是很难的一件事,其它事情稍忙,就很容易说服自己把写博客的计划给推迟了. 好在终于克服了自己的惰性,今天又开始了. 本篇继续我的Luaframework学习之路. 一.规范开发模式 此前的示例中,动态加载的panel都默认以GuiCamera为父节点,且面板的大小设置得有些随意,为方便后续开发,现做一些调整和规范. 1.设定本项目的开发分辨率为1334x750(Game视图分辨率也设置为这个大小): 2.调整相机,将原有的GuiCamera从Canvas下拖离出来

Unity3D热更新全书-脚本(一) 初识脚本

开篇之前还是要先说明,这是一份给经验并不丰富的程序员阅读的文字. 有需求.有疑惑,往下看. 第一个问题什么是脚本?程序和脚本如何区分?我们给Unity编写的组件是程序还是脚本? 这些问题本文无意去解答,因为其中混合着太多有立场的东西,站在不同的立场会有不同的看法,这其中的矛盾不是简单可以调和的. 只要提出一个观点,就很容易陷入语言大战的泥潭. 我们不妨从另一个角度来思考,为什么要分程序和脚本,是为了找一条分界线. 这条分界线叫做灵活. 我们这个专题的出发点是探讨Unity3D客户端资源更新,已这

Unity3D热更新全书-下载 唯一的一篇

下载在这个时代实在是太平常了,每个人都深刻的理解着下载到底是什么. 这一篇文字只是把下载的代码分享并介绍,而已. 首先,下载系统担负着几个使命. 第一.是保持客户端版本库的最新. 第二.是下载要能够比对并最少下载 第三.是要尽量快一些. 其实我们并没有写一个下载系统,因为实在没有几行代码.我们这里介绍的是一个 Http下载并保存缓存,首包从StreamingAssets读取,加载资源,三个功能在一起的模块 源码位置https://github.com/lightszero/easydown 保持

Unity3D热更新全书-脚本(三) C#LightEvil语法与调试

调试,这是一个无法规避的问题 C#Light 由于有 词法解释.语法解释.运行时三种情况 所以和C#也是有类似的问题 出错大致可以分为编译错误和运行时错误 拼写出莫名的东西或者语法不正确,会在编译阶段报错,这种错误很好检查,因为 C#Light语法是C#的严格子集,所有的C#Light脚本都可以用C#的标准做语法检查 这也是C#Light基本上是用VisualStudio做编辑器的原因所在,直接作为C#代码编译,可以排除大部分的语法问题. 然后剩下的一些作为C#代码可以编译过,但是C#Light

Unity3D热更新全书-脚本(五) NGUI

让我们实际的研究一下如何将NGUI和C#LightEvil结合起来. 这里使用NGUI2.7,因为他是一个开源的版本,NGUI最新的版本未经作者的许可,是不可以带入我们的开源项目使用的. 这个例子完成的功能是从NGUI例子里找出了三个界面,按最下方的按钮依次进行切换 这是在之前的框架演示Mode1的基础上做的 由一个状态机去进行驱动,这也是我推荐各位使用脚本的方式. <=这是脚本,也是程序 Mode1的模式是定义一个接口类,然后由脚本继承此类型实现,因为随时考虑AOT的缘故(要兼容IOS),我们