xLua熱更新插件
- 2021 年 2 月 3 日
- 筆記
一.xLua插件下載安裝
1.從GitHub上搜索並下載插件
2.將文件複製到unity中
3.檢查是否有錯誤
二.在unity中調用lua
1.簡單調用
在c#腳本中使用LuaEnv類可以運行lua,建議LuaEnv實例全局唯一。
using System.Collections; using System.Collections.Generic; using UnityEngine; //引入命名空間 using XLua; public class HelloLua01 : MonoBehaviour { //聲明luaenv變數 private LuaEnv luaenv; void Start() { //實例化luaenv變數 luaenv = new LuaEnv(); //調用DoString方法執行lua程式碼 luaenv.DoString("print('hello world!')"); } private void OnDestroy() { //釋放luaenv luaenv.Dispose(); } }
2.lua文件的讀取執行
using UnityEngine; //引入命名空間 using XLua; public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); //將lua程式碼文件放在Resources文件夾下,並添加後綴.txt //通過Resources.Load方法讀取這個文件,聲明類型為TextAsset,這樣讀取的過程中就會自動添加後綴.txt //讀取到文件的內容後轉化為byte數組(使用tostring方法或者text方法轉化為字元串或文本也都可以),並交給DoString方法執行這段程式碼 luaenv.DoString(Resources.Load<TextAsset>("helloLua.lua").bytes); } private void OnDestroy() { luaenv.Dispose(); } }
using UnityEngine; //引入命名空間 using XLua; public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); //使用系統內置的方法載入文件並執行程式碼,文件名是helloLua.lua.txt luaenv.DoString("require 'helloLua'"); } private void OnDestroy() { luaenv.Dispose(); } }
3.自定義Loader:針對文件後綴不是.lua.txt的類型
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); //通過AddLoader方法自定義Loader程式,實際上是將自定義的Loader方法添加到一個委託中 luaenv.AddLoader(MyLoader); //執行DoString方法,會首先調用自定義的Loader方法,如果返回值為空,再調用系統定義的Loader方法 luaenv.DoString("require 'helloLua'"); } //自定義的Loader方法,這個方法返回值必須是byte數組,參數是ref的string類型,傳入文件地址 private byte[] MyLoader(ref string filePath) { print(filePath); return null; } private void OnDestroy() { luaenv.Dispose(); } }
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.AddLoader(MyLoader); luaenv.DoString("require 'helloLua'"); } private byte[] MyLoader(ref string filePath) { //列印文字說明這個loader函數被調用 print("調用了自定義的loader"); //將lua文件放入streaMingAssetsPath文件夾內,拼接好文件的完整絕對路徑 string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt"; //讀取文件,獲得byte數組並返回 return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path)); } private void OnDestroy() { luaenv.Dispose(); } }
4.訪問lua中的變數
1)訪問值類型變數
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //訪問文件中的全局int類型變數a print(luaenv.Global.Get<int>("a")); } private void OnDestroy() { luaenv.Dispose(); } }
2)訪問table形式的變數,可以定義一個對應table的類進行,Get方法會自動new出這個類,並將變數值拷貝進去。
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //獲取表person的內容,存儲為Person類 Person p = luaenv.Global.Get<Person>("person"); print(p.name + p.age); } private void OnDestroy() { luaenv.Dispose(); } //定義一個和表對應好屬性和方法的類 class Person { public string name; public int age; } }
person = { name = 'movin',age = 18 }
3)也可以定義一個對應table屬性和方法的介面,但是介面需要加上[CSharpCallLua]特性,同時lua中定義函數時第一個參數必須是self或者使用冒號定義
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); IPerson p = luaenv.Global.Get<IPerson>("person"); print(p.name + p.age); } private void OnDestroy() { luaenv.Dispose(); } //如果使用介面定義接收的table,必須加上[CSharpCallLua]特性自動生成程式碼 [CSharpCallLua] interface IPerson { string name { get; set; } int age { get; set; } } }
這裡注意:目前xlua沒有支援unity2019版本,這裡程式碼沒有問題,但是運行始終會報錯。
4)使用字典或者鏈表對應table
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //將table轉化為字典 Dictionary<string,object> dict = luaenv.Global.Get<Dictionary<string, object>>("person"); //遍歷輸出 foreach(KeyValuePair<string,object> pair in dict) { print(pair.Key + pair.Value); } } private void OnDestroy() { luaenv.Dispose(); } }
5)使用列表對應table,只能存儲table中沒有鍵的value值
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //將table轉化為list,list只能儲存沒有鍵的table值 List<object> list = luaenv.Global.Get<List<object>>("person"); //遍歷輸出 foreach(Object o in list) { print(o); } } private void OnDestroy() { luaenv.Dispose(); } }
6)使用LuaTable類對應table
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //將table存儲為luatable類的對象 LuaTable tab = luaenv.Global.Get<LuaTable>("person"); //取得其中的鍵對應的值,需要聲明值類型 print(tab.Get<string>("name")); } private void OnDestroy() { luaenv.Dispose(); } }
7)使用委託對應lua中的函數
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //使用委託存儲lua中的函數,函數名稱為add Add add = luaenv.Global.Get<Add>("add"); add(1,3); } //自定義一個委託對應lua中相應的函數,一定要加上[CSharpCallLua]特性 [CSharpCallLua] delegate void Add(int a, int b); private void OnDestroy() { luaenv.Dispose(); } }
2019版本的unity和xlua不兼容,使用更低版本解決問題。
如果lua有不止一個返回值,可以使用out參數或ref參數接收其他的返回值。
8)使用LuaFunction對應lua中的函數
public class HelloLua : MonoBehaviour { private LuaEnv luaenv; void Start() { luaenv = new LuaEnv(); luaenv.DoString("require 'helloLua'"); //xlua提供了LuaFunction對應lua中的函數,使用Call方法調用函數,返回值為一個objec類型的數組 LuaFunction func = luaenv.Global.Get<LuaFunction>("add"); object[] objs = func.Call(1, 3); foreach(object o in objs) { print(o.ToString()); } } private void OnDestroy() { luaenv.Dispose(); } }
三.在lua中調用C#
1.簡單實現調用
1)首先在空物體上掛載腳本,腳本調用lua程式碼
public class LuaCallCSharp : MonoBehaviour { private LuaEnv luaEnv; void Start() { luaEnv = new LuaEnv(); luaEnv.DoString("require 'LuaCallCSharp'"); } private void OnDestroy() { luaEnv.Dispose(); } }
2)然後在lua程式碼中實例化一個遊戲物體
--創建遊戲物體,對應C#中的new UnityEngine.GameObject()程式碼 CS.UnityEngine.GameObject()
3)最後看運行結果
4)注意事項:lua中沒有new關鍵字,所有C#相關的內容都放在了CS下,包括函數、屬性和方法等。對於經常訪問的類,可以先使用局部變數存儲起來,然後再進行調用,減少程式碼量也提高性能。
2.訪問靜態屬性和方法
--對應的C#程式碼:print(UnityEngine.Time.deltaTime); print(CS.UnityEngine.Time.deltaTime) --對應的C#程式碼:UnityEngine.GameObject.Find("Main Camera").name = "fixed by lua" CS.UnityEngine.GameObject.Find("Main Camera").name = "fixed by lua"
3.訪問成員屬性和方法,使用冒號語法糖
local gameObject = CS.UnityEngine.GameObject local camera = gameObject.Find("Main Camera") --調用成員方法使用冒號語法糖(推薦),或者將自身作為第一個參數傳遞(不推薦) local cameraComponent = camera:GetComponent("Camera") gameObject.Destroy(cameraComponent)
4.其他
1)C#中的out參數映射到lua中時不算參數,C#中的out和ref返回值映射到lua中對應多返回值。
2)xlua支援方法的重載
3)支援可變參數
4)lua不支援泛型,但是可以通過Extension methods功能進行封裝後使用
5)C#的委託的調用和普通方法相同,註冊或者移除委託中的方法時需要將「+」或者「-」號作為第一個參數傳遞