xLua使用案例
需引用命名空間XLua
- 簡單案例1 在c#中直接調用lua代碼
LuaEnv luaEnv = null;
private void Start()
{
//建立lua的運作環境 為防止記憶體大量消耗 建議全局裡隻存在一個執行個體
luaEnv = new LuaEnv();
//需要傳遞一個字元串 内容為lua程式
luaEnv.DoString("print('helloxLua')");//通過c#調用lua
luaEnv.DoString(" CS.UnityEngine.Debug.Log('helloxLua') ");//通過lua調用C#
//luaEnv.Dispose();
}
private void OnDestroy()
{
//在代碼執行完後釋放luaEnv
luaEnv.Dispose();
}
- **簡單案例2 ** 通過加載運作lua源檔案
-
通過Resources加載
注:為能使Resources方法能夠讀取到lua檔案 lua檔案字尾需為.lua.txt
private LuaEnv luaenv;
private void Start()
{
luaenv = new LuaEnv();
TextAsset ta = Resources.Load<TextAsset>("helloWorld.lua");
luaenv.DoString(ta.text);
luaenv.Dispose();
}
-
通過loader加載(lua檔案需放在Resources檔案夾 字尾為.lua.txt)
注(引用自xLua作者原話):
require實際上是調一個個的loader去加載,有一個成功就不再往下嘗試,全失敗則封包件找不到。
目前xLua除了原生的loader外,還添加了從Resource加載的loader,需要注意的是因為Resource隻支援有限的字尾,放Resources下的lua檔案得加上txt字尾(見附帶的例子)。
建議的加載Lua腳本方式是:整個程式就一個DoString(“require ‘main’”),然後在main.lua加載其它腳本(類似lua腳本的指令行執行:lua main.lua)。
private LuaEnv luaenv;
private void Start()
{
luaenv = new LuaEnv();
luaenv.DoString("require 'helloWorld'");
luaenv.Dispose();
}
- 簡單案例3 Loader方法
- 添加自定義的Loader方法
private void Start()
{
LuaEnv luaenv = new LuaEnv();
luaenv.AddLoader(Add);//添加自定義Loader方法 傳遞參數是一個委托
luaenv.DoString(" require 'helloWorld'");
luaenv.Dispose();
}
//如果自定義的loader沒有傳回位元組數組 會繼續尋找系統内置的loader
private byte[] Add(ref string filePath)//傳參為lua檔案路徑
{
string s = "print('Add')";//s為lua腳本内容
return System.Text.Encoding.UTF8.GetBytes(s);//将Text文本轉成位元組數組
}
- 通過自定義路徑加載指定目錄的lua檔案
private void Start()
{
LuaEnv luaenv = new LuaEnv();
luaenv.AddLoader(Add);//添加自定義Loader方法 傳遞參數是一個委托
luaenv.DoString(" require 'add'");
luaenv.Dispose();
}
//如果自定義的loader沒有傳回位元組數組 會繼續尋找系統内置的loader
private byte[] Add(ref string filePath)//傳參為lua檔案路徑
{
string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";//得到lua檔案路徑
string s= File.ReadAllText(path);//讀取txt檔案
return System.Text.Encoding.UTF8.GetBytes(s);//将Text文本轉成位元組數組
}
-
簡單案例4 通過c#通路lua中的資料
首先是以下案例中lua的代碼
a=233; str="SKr" now=true; person={ name="小明", age=10, think=function() print("我從哪來?") end, --有參數的方法的第一個參數務必加上self(變量名可以是合法的任意值,但一定要加上這個參數) --self參數代表目前表,在未設定該參數的情況下會作為隐藏參數存在 add=function(arg,a,b) print(a+b) end, 2,4,6,8,10 } function person:add2(a,b) --通過:調用可以不用傳遞參數(),系統會自動傳遞目前的表 print(a+b) end function person.add3(self,a,b) --通過.調用必須傳遞自身,self不會自動指派,我們必須通過第一個參數 print(a+b) end
通過c#通路lua中的全局變量
private void Start()
{
LuaEnv luaenv = new LuaEnv();
luaenv.DoString("require 'CSharpCallLua'");
//擷取lua中的全局變量
int a = luaenv.Global.Get<int>("a");//num對應int float double三個類型
Debug.Log(a);
string str = luaenv.Global.Get<string>("SKr");
Debug.Log(str);
bool now = luaenv.Global.Get<bool>("now");
Debug.Log(now);
luaenv.Dispose();
}
1.通過c#通路lua中的表(映射到普通class或struct)
注:這種方式下xLua會幫你new一個執行個體,并把對應的字段指派過去。這個過程是值拷貝,如果class比較複雜代價會比較大。而且修改class的字段值不會同步到table,反過來也不會。
類
class Person
{
public string name;
public int age;
}
Start函數
Person person = luaenv.Global.Get<Person>("person");
Debug.Log(person);
Debug.Log(person.name);
Debug.Log(person.age);
luaenv.Dispose();
2.通過c#通路lua中的表(映射到接口)
注!:如果改了接口後,之前生成的代碼出現錯誤,執行“Clear Generated Code”菜單!!!
接口
[CSharpCallLua] //lua映射到接口一定要加上這個特性
interface IPerson
{
string name { get; set; }
int age { get; set; }
void think();
}
Start函數
IPerson p = luaenv.Global.Get<IPerson>("person");
Debug.Log(p.name);
p.name = "小李";// 通過c#更改lua中的變量
Debug.Log(p.name);
p.think();//執行lua中的方法
luaenv.Dispose();
lua方法也可以通過以下方式來定義
person={
name="小明",
age=10
}
function person:add2(a,b) --通過:調用可以不用傳遞參數(),系統會自動傳遞目前的表
print(a+b)
end
function person.add3(self,a,b) --通過.調用必須傳遞自身,self不會自動指派,我們必須通過第一個參數來傳遞目前的table
print(a+b)
end
3.通過c#通路lua中的表(映射到Dictionary或者List)
Start函數
...
Dictionary<string, object> dic = luaenv.Global.Get<Dictionary<string, object>("person");
foreach (var item in dic)
{
print(item);//通過dic映射過來的值隻會映射有對應鍵的值
}
List<object> list = luaenv.Global.Get<List<object>>("person");
foreach (var item in list)
{
print(item);/通過list映射過來的值隻會映射沒有對應鍵的值
}
luaenv.Dispose();
...
4.通過c#通路lua中的表(映射到LuaTable類)
注:這種方式好處是不需要生成代碼,但也有一些問題,比如慢,比方式2要慢一個數量級,比如沒有類型檢查。一般情況下推薦使用第二種方式,少用第四種方式
Start函數
...
LuaTable tab = luaenv.Global.Get<LuaTable>("person");
print(tab.Get<string>("name"));
print(tab.Get<int>("age"));
luaenv.Dispose();
...
通過c#通路lua中的全局函數(映射到delegate)
lua
function fun1()
print("fun1!")
end
function fun2(a,b)
print(a+b)
end
function fun3(a,b)
return a+b
end
c#
public class CSharpCallLuaTest : MonoBehaviour
{
LuaEnv luaenv = null;
private void Start()
{
luaenv = new LuaEnv();
luaenv.DoString("require 'CSharpCallLua'");
//無參數委托
Action fun1 = luaenv.Global.Get<Action>("fun1");
fun1();
fun1 = null;//删除c#對lua函數的引用使得lua虛拟機能順利釋放記憶體
//傳參委托
Fun2 fun2 = luaenv.Global.Get<Fun2>("fun2");
fun2(2,4);
fun2 = null;
//傳參委托帶傳回值
Fun3 fun3 = luaenv.Global.Get<Fun3>("fun3");
int res=fun3(2, 4);
print(res);
fun3 = null;
//傳參委托帶多個傳回值
int resC;int resD;
Fun4 fun4 = luaenv.Global.Get<Fun4>("fun4");
//使用out來接受第一個傳回值以外的傳回值 ref同理但要注意賦初值
int resAB = fun4(2, 4,out resC,out resD);
print(resAB);
print(resC);
print(resD);
fun4 = null;
luaenv.Dispose();
}
[CSharpCallLua] //委托必須加上CSharpCallLua特性
delegate void Fun2(int a, int b);
[CSharpCallLua]
delegate int Fun3(int a, int b);
[CSharpCallLua]
delegate int Fun4(int a, int b,out int c,out int d);
通過c#通路lua中的全局函數(映射到LuaFunction)
lua代碼見上文
c#
//通過LuaFunction映射lua方法比較耗費性能 一般不推薦使用
LuaFunction luaFun = luaenv.Global.Get<LuaFunction>("fun4");
object[] calls= luaFun.Call(2, 5);
foreach (var item in calls)
{
print(item);
}
luaenv.Dispose();
xLua作者的使用建議:
1、通路lua全局資料,特别是table以及function,代價比較大,建議盡量少做,比如在初始化時把要調用的lua function擷取一次(映射到delegate)後,儲存下來,後續直接調用該delegate即可。table也類似。
2、如果lua測的實作的部分都以delegate和interface的方式提供,使用方可以完全和xLua解耦:由一個專門的子產品負責xlua的初始化以及delegate、interface的映射,然後把這些delegate和interface設定到要用到它們的地方。
- 簡單案例5 通過lua通路c#中的資料
lua
--需要經常通路的類,可以先用局部變量引用後通路
--所有C#相關的都放到CS下即以CS開頭
local gameObject=CS.UnityEngine.GameObject
--lua裡頭沒有new關鍵字 可以擁有這種方式建立一個GameObject對象
gameObject("new")
--通過lua代碼改變Unity中的相機名字
local camera=gameObject.Find("Main Camera")
--修改camera對象的名字
camera.name="ChangeName"
--得到camera對象的Camera元件 使用:會把目前的對象當作第一個參數傳遞過去
--建議所有的成員方法都通過:來調用
--local cameraCom=camera.GetComponent(camera,"Camera")//用.調用需要傳遞目前對象
local cameraCom=camera:GetComponent("Camera")
--摧毀相機元件
gameObject.Destroy(cameraCom)
c#
private void Start()
{
LuaEnv luaenv = new LuaEnv();
luaenv.DoString("require 'LuaCallCSharp'");
luaenv.Dispose();
}