XLua-操作與使用

C#源代碼->dll->安裝包
Lua源代碼->安裝包

Lua源代碼可以在客戶端直接下載沒有編譯的過程

1.直接用Lua調(diào)用C#的方法
使用XLua輸出HelloWorld
引入命名空間XLua,聲明一個(gè)LuaEnv的類的對象,這個(gè)類提供了一些方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class HellowWorld01 : MonoBehaviour {
    private LuaEnv luaenv;
    void Start () {
        luaenv = new LuaEnv();
        luaenv.DoString("print('hello world')");
        //luaenv.DoString("CS.UnityEngine.Debug.Log('hello kk')");
    }
    private void OnDestroy()
    {
        luaenv.Dispose();
    }
}

輸出結(jié)果:

LUA: hello world

2.通過讀取Lua文件執(zhí)行Lua語句

//加載helloWorld.lua.txt,TextAsset會(huì)自動(dòng)加txt的后綴
        TextAsset ta = Resources.Load<TextAsset>("helloWorld.lua");
        //print(ta);
        LuaEnv luaEnv = new LuaEnv();
        luaEnv.DoString(ta.text);
        luaEnv.Dispose();

3.自定義Loader
在xLua加自定義loader是很簡單的志珍,只涉及到一個(gè)接口:
public delegate byte[] CustomLoader(ref string filepath);
public void LuaEnv.AddLoader(CustomLoader loader)

通過AddLoader可以注冊個(gè)回調(diào)牡直,該回調(diào)參數(shù)是字符串清寇,lua代碼里頭調(diào)用require時(shí)礁芦,參數(shù)將會(huì)透傳給回調(diào),回調(diào)中就可以根據(jù)這個(gè)參數(shù)去加載指定文件坡垫,如果需要支持調(diào)試彭沼,需要把filepath修改為真實(shí)路徑傳出缔逛。該回調(diào)返回值是一個(gè)byte數(shù)組,如果為空表示該loader找不到姓惑,否則則為lua文件的內(nèi)容褐奴。

public class CreateLoader : MonoBehaviour {
    private LuaEnv luaEnv;
    // Use this for initialization
    void Awake () {
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(MyLoader);
        luaEnv.DoString("require 'helloWorld.lua'");
        luaEnv.Dispose();
    }

    private byte[] MyLoader(ref string filePath)
    {
        string s = "print('best kk')";
        return System.Text.Encoding.UTF8.GetBytes(s);
    }
}

4.讀取非Resources文件夾下的lua文件通過自定義Loader

public class CreateLoader : MonoBehaviour {
    private LuaEnv luaEnv;
    void Awake () {
        luaEnv = new LuaEnv();
        luaEnv.AddLoader(MyLoader);
        luaEnv.DoString("require 'test007'");
        luaEnv.Dispose();
    }
    private byte[] MyLoader(ref string filePath)
    {
        print(filePath);
        print(Application.streamingAssetsPath);
        string path = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";
        return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(path));
    }
}

C#訪問Lua

一.獲取Lua中的全局變量

int a = luaEnv.Global.Get<int>("a");
        print(a);

二.訪問一個(gè)全局的Table
在C#中定義一個(gè)類與Lua中的Table相對應(yīng)

 class Person
    {
        public string name;
        public int age;
    }

在用這個(gè)類創(chuàng)建對象來進(jìn)行接收

Person kk = luaEnv.Global.Get<Person>("person");
        print(kk.name + " " + kk.age);

2.使用接口訪問Table
聲明一個(gè)接口,添加CSharpCallLua的特性

    [CSharpCallLua]
    interface IPerson
    {
        string name { get; set; }
        int age { get; set; }
    }

使用接口將獲取Lua文件中的引用于毙,這與通過聲明類不同敦冬,修改實(shí)例化的接口將直接修改Lua中的數(shù)據(jù)。
在接口中聲明方法將直接對應(yīng)Lua中Table中的方法唯沮。

person = {
    name = "kk";
    age = 23;
    eat = function()
        print("111");
    end
}
    [CSharpCallLua]
    interface IPerson
    {
        string name { get; set; }
        int age { get; set; }
        void eat();
    }

3.使用輕量級的映射方式字典或者集合
將Lua中Table的鍵值對存在Dictionary中脖旱,存在限制,沒有明確的鍵的無法存在Dictionary中介蛉。

        Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string,object>>("person");
        foreach (string item in dic.Keys)
        {
            print(item + " " + dic[item]);
        }

將Lua中Table的鍵值對存在List中萌庆,List中只能存沒有明確鍵的。只能映射值币旧,沒有key的践险。

        List<object> list = luaEnv.Global.Get<List<object>>("person");
        foreach (var item in list)
        {
            print(item);
        }

4.另一種by ref方式:映射到LuaTable類

        LuaTable luaTable = luaEnv.Global.Get<LuaTable>("person");
        print(luaTable.Get<string>("name"));
        print(luaTable.Get<string>("age"));

在LuaTable中可以通過.GetInPath獲得表中表

person = {
    man = {height = 100;};
    name = "kk";
    age = 23,
    2,
    3,
    4,
    56,
    eat = function()
        print("111");
    end
}
print(luaTable.GetInPath<int>("man.height"));

三.訪問一個(gè)全局的function
1.映射到delegate
在C#中delegate的參數(shù)與Lua中的funciton的參數(shù)對應(yīng)即可

Action act1 = luaEnv.Global.Get<Action>("add");
act1();
act1 = null;//釋放對Lua的引用

在Lua中的方法需要傳參的時(shí)候:

function add(a,b)
    print(a+b);
end

在定義委托的時(shí)候就用delegate并添加CSharpCallLua的特性

[CSharpCallLua]
    delegate void Add(int a, int b);

接受返回值

function add(a,b)
    print(a+b);
    return 666;
end
[CSharpCallLua]
    delegate int Add(int a, int b);

多返回值
使用ref或out參數(shù)接受多的返回值

function add(a,b)
    print(a+b);
    return 666,a,b;
end
 [CSharpCallLua]
    delegate int Add(int a, int b,out int resa,out int resb);
Add add = luaEnv.Global.Get<Add>("add");
        //print (add(3, 2));
        int resa;
        int resb;
        int ans = add(6,9,out resa,out resb);
        print(resa + "__" + resb);

2.映射到LuaFunction
調(diào)用起來比較慢,LuaFunction上有個(gè)變參Call函數(shù),可以傳任意類型捏境,任意個(gè)數(shù)的參數(shù)于游,返回值是object的數(shù)組毁葱,對應(yīng)于lua的多返回值垫言。

四.使用建議
C#調(diào)用Lua全局的變量代價(jià)較大盡量少做,可以的話可以講Lua中的變量存起來避免重復(fù)的映射倾剿。適用方于xLua解耦筷频。

Lua訪問C#

newC#對象
在Lua中創(chuàng)建一個(gè)游戲物體:

CS.UnityEngine.GameObject()

lua中沒有new關(guān)鍵字。
所有C#相關(guān)都放到CS下前痘,包括構(gòu)造函數(shù)凛捏、靜態(tài)成員屬性、方法
xlua支持重載

訪問C#靜態(tài)屬性芹缔、方法
Lua中調(diào)用某一個(gè)對象中的方法要通過:的方式進(jìn)行調(diào)用坯癣。

new C#對象
你在C#這樣new一個(gè)對象:
var newGameObj = new UnityEngine.GameObject();
對應(yīng)到Lua是這樣:
local newGameObj = CS.UnityEngine.GameObject()
基本類似,除了:
1最欠、lua里頭沒有new關(guān)鍵字示罗;
2、所有C#相關(guān)的都放到CS下芝硬,包括構(gòu)造函數(shù)蚜点,靜態(tài)成員屬性、方法拌阴;
如果有多個(gè)構(gòu)造函數(shù)呢绍绘?放心,xlua支持重載迟赃,比如你要調(diào)用GameObject的帶一個(gè)string參數(shù)的構(gòu)造函數(shù)陪拘,這么寫:
local newGameObj2 = CS.UnityEngine.GameObject('helloworld')

訪問C#靜態(tài)屬性,方法
讀靜態(tài)屬性
CS.UnityEngine.Time.deltaTime
寫靜態(tài)屬性
CS.UnityEngine.Time.timeScale = 0.5
調(diào)用靜態(tài)方法
CS.UnityEngine.GameObject.Find('helloworld')
小技巧:如果需要經(jīng)常訪問的類纤壁,可以先用局部變量引用后訪問藻丢,除了減少敲代碼的時(shí)間,還能提高性能:
local GameObject = CS.UnityEngine.GameObject
GameObject.Find('helloworld')

訪問C#成員屬性摄乒,方法
讀成員屬性
testobj.DMF
寫成員屬性
testobj.DMF = 1024
調(diào)用成員方法
注意:調(diào)用成員方法悠反,第一個(gè)參數(shù)需要傳該對象,建議用冒號(hào)語法糖馍佑,如下
testobj:DMFunc()
父類屬性斋否,方法
xlua支持(通過派生類)訪問基類的靜態(tài)屬性,靜態(tài)方法拭荤,(通過派生類實(shí)例)訪問基類的成員屬性茵臭,成員方法
參數(shù)的輸入輸出屬性(out,ref)
Lua調(diào)用測的參數(shù)處理規(guī)則:C#的普通參數(shù)算一個(gè)輸入形參舅世,ref修飾的算一個(gè)輸入形參旦委,out不算奇徒,然后從左往右對應(yīng)lua 調(diào)用測的實(shí)參列表;
Lua調(diào)用測的返回值處理規(guī)則:C#函數(shù)的返回值(如果有的話)算一個(gè)返回值缨硝,out算一個(gè)返回值摩钙,ref算一個(gè)返回值,然后從左往右對應(yīng)lua的多返回值查辩。

重載方法
直接通過不同的參數(shù)類型進(jìn)行重載函數(shù)的訪問胖笛,例如:
testobj:TestFunc(100)
testobj:TestFunc('hello')
將分別訪問整數(shù)參數(shù)的TestFunc和字符串參數(shù)的TestFunc。
注意:xlua只一定程度上支持重載函數(shù)的調(diào)用宜岛,因?yàn)閘ua的類型遠(yuǎn)遠(yuǎn)不如C#豐富长踊,存在一對多的情況,比如C#的int萍倡,float身弊,double都對應(yīng)于lua的number,上面的例子中TestFunc如果有這些重載參數(shù)列敲,第一行將無法區(qū)分開來阱佛,只能調(diào)用到其中一個(gè)(生成代碼中排前面的那個(gè))

操作符
支持的操作符有:+,-酿炸,*瘫絮,/,==填硕,一元-麦萤,<,<=扁眯, %壮莹,[]

參數(shù)帶默認(rèn)值的方法
和C#調(diào)用有默認(rèn)值參數(shù)的函數(shù)一樣,如果所給的實(shí)參少于形參姻檀,則會(huì)用默認(rèn)值補(bǔ)上命满。
可變參數(shù)方法
對于C#的如下方法:
void VariableParamsFunc(int a, params string[] strs)
可以在lua里頭這樣調(diào)用:
testobj:VariableParamsFunc(5, 'hello', 'john')
使用Extension methods
在C#里定義了,lua里就能直接使用绣版。
泛化(模版)方法
不直接支持胶台,可以通過Extension methods功能進(jìn)行封裝后調(diào)用。

枚舉類型
枚舉值就像枚舉類型下的靜態(tài)屬性一樣杂抽。
testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
上面的EnumTestFunc函數(shù)參數(shù)是Tutorial.TestEnum類型的
另外诈唬,如果枚舉類加入到生成代碼的話,枚舉類將支持__CastFrom方法缩麸,可以實(shí)現(xiàn)從一個(gè)整數(shù)或者字符串到枚舉值的轉(zhuǎn)換铸磅,例如:
CS.Tutorial.TestEnum.__CastFrom(1)
CS.Tutorial.TestEnum.__CastFrom('E1')

delegate使用(調(diào)用,+,-)
C#的delegate調(diào)用:和調(diào)用普通lua函數(shù)一樣
+操作符:對應(yīng)C#的+操作符阅仔,把兩個(gè)調(diào)用串成一個(gè)調(diào)用鏈吹散,右操作數(shù)可以是同類型的C# delegate或者是lua函數(shù)。
-操作符:和+相反八酒,把一個(gè)delegate從調(diào)用鏈中移除空民。
Ps:delegate屬性可以用一個(gè)luafunction來賦值。

event
比如testobj里頭有個(gè)事件定義是這樣:public event Action TestEvent;
增加事件回調(diào)
testobj:TestEvent('+', lua_event_callback)
移除事件回調(diào)
testobj:TestEvent('-', lua_event_callback)

64位整數(shù)支持
Lua53版本64位整數(shù)(long丘跌,ulong)映射到原生的64未整數(shù)袭景,而luaji版本t唁桩,相當(dāng)于lua5.1的標(biāo)準(zhǔn)闭树,本身不支持64位,xlua做了個(gè)64位支持的擴(kuò)展庫荒澡,C#的long和ulong都將映射到userdata:
1报辱、支持在lua里頭進(jìn)行64位的運(yùn)算,比較单山,打印
2碍现、支持和lua number的運(yùn)算,比較
3米奸、要注意的是昼接,在64擴(kuò)展庫中,實(shí)際上只有int64悴晰,ulong也會(huì)先強(qiáng)轉(zhuǎn)成long再傳遞到lua慢睡,而對ulong的一些運(yùn)算,比較铡溪,我們采取和java一樣的支持方式漂辐,提供一組API,詳情請看API文檔棕硫。

C#復(fù)雜類型和table的自動(dòng)轉(zhuǎn)換
對于一個(gè)有無參構(gòu)造函數(shù)的C#復(fù)雜類型髓涯,在lua側(cè)可以直接用一個(gè)table來代替,該table對應(yīng)復(fù)雜類型的public字段有相應(yīng)字段即可哈扮,支持函數(shù)參數(shù)傳遞纬纪,屬性賦值等,例如:
C#下B結(jié)構(gòu)體(class也支持)定義如下:
public struct A
{
public int a;
}

public struct B
{
public A b;
public double c;
}
某個(gè)類有成員函數(shù)如下:
void Foo(B b)
在lua可以這么調(diào)用
obj:Foo({b = {a = 100}, c = 200})

獲取類型(相當(dāng)于C#的typeof)
比如要獲取UnityEngine.ParticleSystem類的Type信息滑肉,可以這樣
typeof(CS.UnityEngine.ParticleSystem)

“強(qiáng)”轉(zhuǎn)
lua沒類型包各,所以不會(huì)有強(qiáng)類型語言的“強(qiáng)轉(zhuǎn)”,但有個(gè)有點(diǎn)像的東西:告訴xlua要用指定的生成代碼去調(diào)用一個(gè)對象赦邻,這在什么情況下能用到呢髓棋?有的時(shí)候第三方庫對外暴露的是一個(gè)interface或者抽象類,實(shí)現(xiàn)類是隱藏的,這樣我們無法對實(shí)現(xiàn)類進(jìn)行代碼生成按声。該實(shí)現(xiàn)類將會(huì)被xlua識(shí)別為未生成代碼而用反射來訪問膳犹,如果這個(gè)調(diào)用是很頻繁的話還是很影響性能的,這時(shí)我們就可以把這個(gè)interface或者抽象類加到生成代碼签则,然后指定用該生成代碼來訪問:
cast(calc, typeof(CS.Tutorial.Calc))
上面就是指定用CS.Tutorial.Calc的生成代碼來訪問calc對象须床。

EG:在VSCode中找到files.associations文件,在settings.json中添加

{
    "files.associations": {"*.lua.txt":"lua"}
}

就可以在txt文件中編寫lua代碼并顯示高亮了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渐裂,一起剝皮案震驚了整個(gè)濱河市豺旬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柒凉,老刑警劉巖族阅,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異膝捞,居然都是意外死亡坦刀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進(jìn)店門蔬咬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲤遥,“玉大人,你說我怎么就攤上這事林艘「悄危” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵狐援,是天一觀的道長钢坦。 經(jīng)常有香客問我,道長咕村,這世上最難降的妖魔是什么场钉? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮懈涛,結(jié)果婚禮上逛万,老公的妹妹穿的比我還像新娘。我一直安慰自己批钠,他們只是感情好宇植,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著埋心,像睡著了一般指郁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拷呆,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天闲坎,我揣著相機(jī)與錄音疫粥,去河邊找鬼。 笑死腰懂,一個(gè)胖子當(dāng)著我的面吹牛梗逮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播绣溜,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼慷彤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了怖喻?” 一聲冷哼從身側(cè)響起底哗,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎锚沸,沒想到半個(gè)月后跋选,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咒吐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年野建,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了属划。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恬叹。...
    茶點(diǎn)故事閱讀 40,503評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖同眯,靈堂內(nèi)的尸體忽然破棺而出绽昼,到底是詐尸還是另有隱情,我是刑警寧澤须蜗,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布硅确,位于F島的核電站,受9級特大地震影響明肮,放射性物質(zhì)發(fā)生泄漏菱农。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一柿估、第九天 我趴在偏房一處隱蔽的房頂上張望循未。 院中可真熱鬧,春花似錦秫舌、人聲如沸的妖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嫂粟。三九已至,卻和暖如春墨缘,著一層夾襖步出監(jiān)牢的瞬間星虹,已是汗流浹背零抬。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宽涌,地道東北人媚值。 一個(gè)月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像护糖,于是被迫代替她去往敵國和親褥芒。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容