XLua下載地址:https://github.com/Tencent/xLua
下載后接下來就是導入XLua到unity里了蓄愁,解析出來的XLua有下面幾個文件夾
我們只需要將Assests:主目錄里面的東西全部導入到Unity里面就OK了竭恬,導入后再XLua的文件夾下有這么幾個戳鹅。里面都有學習的文檔,也可自行去學。
hotfix的環(huán)境配置
在unity的PlayerSetting下的Other Settings里面打開XLua的宏HOTFIX_ENABLE,只有打開這個宏以后才能進行Xlua的修復以及更新
定義后后生成代碼并注入
使用建議
對所有較大可能變動的類型加上[Hotfix]標識而涉;
建議用反射找出所有函數(shù)參數(shù)、字段瞳秽、屬性瓣履、事件涉及的delegate類型,在C#函數(shù)中調用Lua练俐,在C#函數(shù)上標注[CSharpCallLua]袖迎;
業(yè)務代碼、引擎API腺晾、系統(tǒng)API燕锥,需要在Lua補丁里頭高性能訪問的類型,在Lua中調用C#函數(shù)悯蝉,在C#函數(shù)上標注加上[LuaCallCSharp]归形;
引擎API、系統(tǒng)API可能被代碼剪裁調(C#無引用的地方都會被剪裁)鼻由,如果覺得可能會新增C#代碼之外的API調用连霉,這些API所在的類型要么加LuaCallCSharp,要么加ReflectionUse嗡靡;
開發(fā)過程:
首先開發(fā)業(yè)務代碼->在所有可能出現(xiàn)問題的類上打上hotfix的標簽跺撼,在所有l(wèi)ua調用CSharp的方法上打上LuaCallCSharp,在所有CSharp調用Lua的方法上打上CSharpCallLua->打包發(fā)布->修改bug時只需要更新Lua文件,修改資源時(聲音讨彼,模型歉井,貼圖,圖片哈误,UI)只需要更新ab包哩至。用戶只需要去下載lua文件跟ab包。
C#訪問Lua中的全局變量與table
首先創(chuàng)建一個在Resources下面創(chuàng)建一個文本文件并給其命名為Hello world.lua.txt蜜自,這樣我們就可以讀取到Lua文本文件了菩貌,然后寫入以下
print("hello world from file")
a=100
Str="NiHao"
IsDie=false
person=
{
name="Tao",age=20,
eat=function(self,a,b) --一個函數(shù) self代表自身 隱藏參數(shù) 后面再跟兩個int參數(shù)
print(a+b)
print("OK")
end
}
接著我們創(chuàng)建一個腳本HolloworldXLua引入程序集XLua在Start方法下寫入
一個LuaEnv實例對應Lua虛擬機,出于開銷的考慮重荠,建議全局唯一
DoString參數(shù)為String箭阶,可輸入任意合法的Lua代碼.
using UnityEngine;
using XLua;
public class HolloworldXLua: MonoBehaviour {
// Use this for initialization
void Start () {
LuaEnv luaenv = new LuaEnv();//一個LuaEnv實例對應Lua虛擬機,出于開銷的考慮戈鲁,建議全局唯一
luaenv.DoString("require 'Hello world'");//通過內置的Loder加載lua源文件
int a = luaenv.Global.Get<int>("a");//獲取到Lua里面的全局變量a
Debug.Log(a);
string Str = luaenv.Global.Get<string>("Str");
Debug.Log(Str);
bool IsDie = luaenv.Global.Get<bool>("IsDie");
Debug.Log(IsDie);
//Person p = luaenv.Global.Get<Person>("person");
IPerson p = luaenv.Global.Get<IPerson>("person");
Debug.Log(p.name+p.age);
p.eat(12,22);//調用Lua里面的函數(shù) p.eat(p,12,22)有隱藏參數(shù)
luaenv.Dispose();
}
class Person
{
public string name;
public int age;
}
//獲取Lua里面的列表用接口也可以映射的仇参,但是要加上CSharpCallLua
[CSharpCallLua]
interface IPerson
{
string name { get; set; }
int age { get; set; }
void eat(int a,int b);
}
}
在這里訪問Lua中的Table有幾種方法一種是映射到類中,另一種是映射到接口中去婆殿,但是這兩種方法結果都是相同但是诈乒,有一點是不一樣的,那就是映射到類中只拷貝Lua里面的數(shù)據(jù)但是用接口映射的話可以修改Lua里面的數(shù)據(jù).,用接口相當與引用
然后我們就可以看到輸出的結果婆芦,輸出的就是Lua腳本里面的全局變量與里面的table里面的
然后還可以通過Dictionary或者List去映射Lua表里面的數(shù)據(jù)
void Start()
{
LuaEnv luaenv = new LuaEnv();//一個LuaEnv實例對應Lua虛擬機怕磨,出于開銷的考慮喂饥,建議全局唯一
luaenv.DoString("require 'Hello world'");//通過內置的Loder加載lua源文件
Dictionary<string, object> dict = luaenv.Global.Get<Dictionary<string, object>>("person");//person表示哪個表
foreach (string Key in dict.Keys)
{
print(Key + ":" + dict[Key]);
}
luaenv.Dispose();
}
輸出結果:
下面使用List也可以映射那些沒有Key的值,
Lua腳本里面
print("hello world from file")
a=100
Str="NiHao"
IsDie=false
person=
{
name="Tao",age=20,2,2,212,15
}
function person:eat(a,b)
print(a+b)
end
C#腳本里面
void Start()
{
LuaEnv luaenv = new LuaEnv();//一個LuaEnv實例對應Lua虛擬機,出于開銷的考慮肠鲫,建議全局唯一
luaenv.DoString("require 'Hello world'");//通過內置的Loder加載lua源文件
List<object> list = luaenv.Global.Get<List<object>>("person");//person表示哪個表
foreach (object o in list)
{
print(o);
}
luaenv.Dispose();
}
最后輸出可以看到2輸出兩次212和15分別輸出一次對應Lua腳本里面的數(shù)據(jù):
還有一種訪問Tab的方式就是使用LuaTable,這種方式不推薦使用仰泻,性能比較慢,我推薦使用第二種方式通過去創(chuàng)建Intaface去映射Lua中的Table滩届。
訪問一個全局的Function
首先Lua腳本里面寫入函數(shù)方法,一個有多個返回值有參數(shù)的方法
function add(a,b)
print(a+b)
return a+b,a,b
end
那么在C#中如何去調用呢下面來看看摘昌,因為我們在C#中只能有一個返回值而在Lua中可以有多個返回值件蚕,那么在C#返回值的時候只能返回第一個值斩披,而Lua后面的返回值可以在C#中用out或者ref去接收后面的返回值
[CSharpCallLua]
delegate int Add(int a, int b,out int resa,out int resb);//定義一個有返回值有參數(shù)的委托
void Start()
{
LuaEnv luaenv = new LuaEnv();//一個LuaEnv實例對應Lua虛擬機设褐,出于開銷的考慮,建議全局唯一
luaenv.DoString("require 'Hello world'");//通過內置的Loder加載lua源文件
Add add = luaenv.Global.Get<Add>("add");
int resa, resb;
int res=add(12,15,out resa,out resb);
print(res);
print(resa);
print(resb);
add = null;//Action有映射如果直接釋放Lua虛擬機的話直接會報錯只有將Action函數(shù)置空后才能釋放虛擬機
luaenv.Dispose();
}
輸出結果,前面兩個是Lua里面輸出的泡挺,后面是C#里面輸出的辈讶,這樣就輕松調用了Lua里面的方法了
還有一種方式就是使用Lua自帶的LuaFction,和上面LuaTable使用一樣比較耗費性能娄猫,但是使用簡單所以這里也不推薦使用
添加自定義Load的方法
如果我們的Lua文本不想放在Resource里面加載想放到其他地方加載怎么辦呢贱除,Xlua也提供了自定義的Load方法,比如我們想把我們的Lua腳本放在StreamingAssets文件夾下面媳溺,那么該如何做呢月幌,首先先在Unity里面創(chuàng)建一個StreamingAssets文件夾,然后把我們的Lua腳本放在StreamingAssets文件夾下悬蔽,創(chuàng)建一個腳本CreateLoade,寫入代碼
private LuaEnv luaenv;
// Use this for initialization
void Start () {
luaenv = new LuaEnv();
luaenv.AddLoader(MyLoader);//添加自己的Load
luaenv.DoString("require 'hello world'");
}
private byte[] MyLoader(ref string filePath)
{
// Application.streamingAssetsPath表示找到Asses里面的StreamingAssets
string absPath = Application.streamingAssetsPath + "/" + filePath + ".lua.txt";
return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath)); ;
}
private void OnDestroy()
{
luaenv.Dispose();
}
然后我們在Unity里面運行起來看結果,輸出了Lua腳本里輸出的結果扯躺。這樣就沒問題了.
在Lua中構造Unity里面游戲物體并且查找游戲對象獲取相應組件
在Lua腳本中寫入
--構造游戲物體,New一個對象
CS.UnityEngine.GameObject("NewByLua")
--訪問靜態(tài)屬性
print(CS.UnityEngine.Time.deltaTime)
--局部變量 訪問Unity里面的游戲物體
local gameobject=CS.UnityEngine.GameObject
local camera=gameobject.Find("Main Camera")
local light=gameobject.Find("Directional Light")
light.name="UpdataLight"
--獲取light游戲物體里面的Light組件 調用成員方法的時候,使用冒號
local lightCom=light:GetComponent("Light")
--銷毀lightCom組件
gameobject.Destroy(lightCom)
這時候C#中構造虛擬機運行的時候就會在Unity里面構造一個空的游戲物體,運行后會生成一個名為NewByLua的空游戲物體蝎困,并且會查找到Directional Light并修改名為為UpdataLight,并移除了里面的Light組件