unity3d熱更新插件uLua學習整理


  

  (2015-02-10 22:48:47)
標簽: 

it

 

tolua

 

ulua

 

unity3d

 

熱更新

分類: unity3d
前言

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#里寫的數組類型

unity3d熱更新插件uLua學習整理

核心思想就是把你C#數組里面的東西,放入table,如果是單純的數據類型,你可以直接lua里面for 0,maxlength  如果是字典類型的,你就要轉換。

比如我這里:

unity3d熱更新插件uLua學習整理

通過TOLUA,把Collider2d類型注冊給ULUA,直接lua里面for 0,maxlength 遍歷。

unity3d熱更新插件uLua學習整理

再貼上ULUA群主寫的范例:

unity3d熱更新插件uLua學習整理

在lua里怎么遍歷 C#的object數組:

unity3d熱更新插件uLua學習整理
通過 IEnumerator:

unity3d熱更新插件uLua學習整理  

uLua自帶的案例

2015年3月26日 15:58:22 補充說明,升級到U3D5.0.0F4,U3D API改了很多,都得用getcomponent函數,以前直接THIS.transform已經不能用了,所以自帶的小案例會報錯。

unity3d熱更新插件uLua學習整理

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報錯:

unity3d熱更新插件uLua學習整理

修改打包編輯器腳本:

unity3d熱更新插件uLua學習整理

unity3d熱更新插件uLua學習整理

unity3d熱更新插件uLua學習整理


unity3d熱更新插件uLua學習整理

直接簡單的把打包目標改成WIN,重新打包。

載入AB的資源管理腳本:

unity3d熱更新插件uLua學習整理

unity3d熱更新插件uLua學習整理

unity3d熱更新插件uLua學習整理
可以看到這里對路徑只寫了安卓和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”或它的某一個依賴項。系統找不到指定的文件。 

unity3d熱更新插件uLua學習整理

安裝。net 4沒有找到jsondll ,已經在目錄里面有了,跟exe同目錄

unity3d熱更新插件uLua學習整理

 

把這個,Newtonsoft.Json.dll考到 debug執行文件 同目錄就可以了。

unity3d熱更新插件uLua學習整理

 

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

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

unity3d熱更新插件uLua學習整理
-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替換其底層庫,可暫時繞過此問題,將來有時間研究下


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM