1. 程式人生 > >Unity3D學習筆記(三十一):Xlua(1)

Unity3D學習筆記(三十一):Xlua(1)

免費 最終 object delta urn 自動 assets 文件的 span

Xlua:騰訊研發,開源免費 配置:文件解壓,拷貝到Unity項目裏 註意:Xlua文件夾不許移動,不許重命名 運行Xlua: 1、引用命名空間 2、創建虛擬機 3、運行lua語句 4、不需要時,釋放虛擬機(LuaEnv:Lua的虛擬機)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;//1、引用Xlua的命名空間
public class HelloWorld : MonoBehaviour
{
    //lua的語句
    private string
lua = @"print(‘Hello World‘) return 1, ‘nihao‘, true"; //2、創建一個運行lua語句的lua虛擬機 private LuaEnv luaEnv = new LuaEnv(); void Start() { //4、運行lua的語句 //這個方法的參數就是lua的語句,返回值就是運行lua,lua裏的最終的返回內容 object[] obj_arr = luaEnv.DoString(lua); foreach (var item in obj_arr) { Debug.Log(item); } }
private void OnDestroy() { //3、不需要虛擬機的時候,需要把虛擬機釋放掉 luaEnv.Dispose(); } }
C#調用Lua的文件: 1、Lua文件的後綴必須是.lua.txt的,file.lua.txt 2、Lua文件必須放在Resources文件夾下,不可以是子文件夾,默認加載器的原因 3、Lua文件的默認編碼格式必須是UTF-8的。 4、使用Lua的關鍵字require調用,不需要寫文件後綴,只需要寫文件名 ----例如:file.lua.txt; require ‘file‘ 5、對於文件的返回值,需要寫成 return require ‘file‘才能獲得 技術分享圖片

技術分享圖片

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaByFile : MonoBehaviour
{
    private string lua = @"require ‘LuaByFile‘";
  //private string lua = @"a = require ‘LuaByFile‘ retrun a";

    //private string lua = @"retrun require ‘LuaByFile‘";
    private LuaEnv luaEnv = new LuaEnv();

    void Start()
    {
        object[] obj_arr = luaEnv.DoString(lua);
    }

    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}
自定義的加載器:能執行我們想要執行的指定文件夾下的Lua文件 自定義的加載器的參數:require傳入的文件名 自定義的加載器的返回值:要執行的Luad的語句轉換成的字節數組(UTF-8轉換),如果返回null。證明未找到文件。 一個lua虛擬機能添加無數個自定義加載器,從第一個加載器中開始找,如果找到了(未返回null),那麽就不執行之後的其他的加載器,如果所有的自定義的加載器都未找到,執行默認的加載器,從Resources文件夾中尋找文件,如果默認的也未找到,直接報錯。 .lua.txt文件打成AB包 技術分享圖片
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
using System.Text;
public class CustomeLoader : MonoBehaviour {


    private LuaEnv luaEnv = new LuaEnv();
    //該文件不在Resources下,默認加載器加載不到
    private string lua = @"require ‘CustomeLoader2‘";

    void Start () {
        //添加一個自定義的加載器
        luaEnv.AddLoader(CustomeLoader1);
        luaEnv.AddLoader(CustomeLoader2);
        luaEnv.DoString(lua);
    }


    private void OnDestroy()
    {
        luaEnv.Dispose();
    }


    /// <summary>
    /// 自定義的加載器
    /// </summary>
    /// <param name="filePath">參數是require後的那個文件名字</param>
    /// <returns></returns>
    /// 返回值就是要執行的lua的轉換之後的字節數組,如果返回值是null證明我們未找到該lua文件
    byte[] CustomeLoader1(ref string filePath)
    {
        //filePath:參數是require後的那個文件名字
        //byte[] bytes = System.Text.Encoding.UTF8.GetBytes("print(‘hello world‘)");
        //文件所在的絕對路徑
        string path = Application.streamingAssetsPath + "/Lua/" + filePath + ".lua.txt";
        if (!File.Exists(path))
        {
            return null;//如果不存在該文件,直接返回null
        }
        StreamReader sr = new StreamReader(path, System.Text.Encoding.UTF8);
        string lua = "";
        try
        {
            lua = sr.ReadToEnd();
        }
        catch (System.Exception)
        {
            throw;
        }
        sr.Close();
        if (lua == "")//如果讀取內容為空串,那麽返回null,證明未找到該文件
        {        
            return null;
        }
        else
        {
            byte[] bytes = System.Text.Encoding.UTF8.GetBytes(lua);
            return bytes;
        }
    }


    /// <summary>
    /// 從ab包中加載lua文件
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    byte[] CustomeLoader2(ref string filePath)
    {
        //加載AB包
        AssetBundle ab = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/AB/lua");
        //從ab包中加載所需要的lua文件
        TextAsset lua = ab.LoadAsset<TextAsset>(filePath + ".lua");
        if (lua != null)
        {
            return lua.bytes;
        }
        return null;
    }
}
C#訪問Lua文件裏的變量和方法: C#訪問Lua的全局變量 虛擬機執行一個lua語句之後,lua裏的全局的變量或方法, 都存放在luaEnv.Global中,從Global中獲取這些全的變量或方法。 CSharpCallLuaVariate.lua.txt
print(開始執行Variate.lua)
a = 1
b = 1.2
c = true
d = 小明
print(開始執行Variate.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLuaVariate : MonoBehaviour {


    private LuaEnv luaEnv = new LuaEnv();

    void Start () {
        luaEnv.DoString("require ‘CSharpCallLuaVariate‘");
        //虛擬機執行一個lua語句之後,lua裏的全局的變量或方法
        //都存放在luaEnv.Global中,從Global中獲取這些全的變量或方法
        //泛型是要接收的變量類型,參數是lua裏的變量名字
        //返回值就是變量的值
        //int
        int a = luaEnv.Global.Get<int>("a");
        Debug.Log("a: " + a);
        //float
        float b = luaEnv.Global.Get<float>("b");
        Debug.Log("b: " + b);
        //bool
        bool c = luaEnv.Global.Get<bool>("c");
        Debug.Log("c: " + c);
        //string
        string d = luaEnv.Global.Get<string>("d");
        Debug.Log("d: " + d);
    }
       
    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}
C#訪問全局的table 1、映射到類或結構體中(值拷貝過程) 只能把table中的鍵值對映射到類中的公共變量,並且變量名與鍵名一致。 對於類中如果變量多於table的鍵值對,table鍵值對多余類中變量,都沒有任何的影響 2、使用接口映射 不光能映射基本類型,還能映射table中的方法。 Table中的鍵與接口中的屬性名或方法名對應上。 3、使用字典或list映射 List映射:只能映射索引的數字且連續的,並且只能映射值與list指定了類型一致的元素。 字典映射:當指定了字典的鍵類型和值類型之後,table中鍵與字典的鍵的類型一致,且鍵對應的值的類型與字典中值類型一致的也會映射過來。 4、使用XLua提供的LuaTable來映射 CSharpCallLuaTable.lua.txt
print(開始執行CSharpCallLuaTable.lua)
t1 = {1, 2, 5, "小明", "nihao"}
t1.f1 = "name"
t1.f2 = true
t1.id = 1
t1[6] = 6
t1[9] = 9
t1.func1 = function()
    print("func1")
end
print(開始執行CSharpCallLuaTable.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLuaTable : MonoBehaviour {


    private LuaEnv luaEnv = new LuaEnv();


    void Start()
    {
        luaEnv.DoString("require ‘CSharpCallLuaTable‘");


        //1、使用class或struct去映射table(值拷貝過程)
        T1 t1 = luaEnv.Global.Get<T1>("t1");
        t1.Print();


        //2、可以使用接口去映射(引用拷貝過程)
        IT1 it1 = luaEnv.Global.Get<IT1>("t1");
        Debug.Log("it1:f1: " + it1.f1 + ",f2: " + it1.f2 + ",id: " + it1.id);
        it1.func1();


        //3、映射到字典或List中(值拷貝過程)
        List<object> list = luaEnv.Global.Get<List<object>>("t1");
        foreach (var item in list)
        {
            Debug.Log("list: " + item);
        }
        Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string, object>>("t1");
        foreach (KeyValuePair<string, object> item in dic)
        {
            Debug.Log("鍵: " + item.Key + "值: " + item.Value);
        }


        //4、使用XLua提供的LuaTable來映射
        LuaTable lt = luaEnv.Global.Get<LuaTable>("t1");
        //對於table中字符串作為鍵的鍵值對
        string f1 = lt.Get<string>("f1");
        Debug.Log("f1: " + f1);
        //對於table中的數字類型的索引的鍵值對,在取的時候需要指定鍵的類型和值的類型
        string a = lt.Get<int, string>(4);
        Debug.Log("第四個索引: " + a);
    }
    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
    public class T1
    {
        public string f1;
        public bool f2;
        public int id;
        public void Print()
        {
            Debug.Log("f1: " + f1 + ",f2: " + f2 + ",id: " + id);
        }
    }
    [CSharpCallLua]//需要添加此特性
    public interface IT1//接口裏不能有變量,可以用變量
    {
        string f1 { get; set; }
        bool f2 { get; set; }
        int id { get; set; }
        void func1();
    }
}
C#映射全局的方法 1、使用委托映射 Lua中多返回值的情況:如果C#的委托有返回值,那麽lua的函數的第一個返回值就是委托的返回值,第二個返回值之後依次對應委托裏的out或ref參數傳出。 如果C#的委托是無返回值的,那麽lua函數從第一個返回值開始,依次對應委托的out或ref參數傳出。 2、使用LuaFunction映射 CSharpCallLuaFunction.lua.txt
print(開始執行CSharpCallLuaFunction.lua)

--無參無返回值
func1 = function()
    print("無參無返回值:func1")
end

--有參無返回值
func2 = function(a, b)
    print("有參無返回值:func2:", a, b)
end

--無參有返回值
func3 = function()
    print("無參有返回值:func3")
    return 1
end

--有參有返回值
func4 = function(a, b)
    print("有參有返回值:func4:", a, b)
    return true
end

--無參多返回值
func5 = function()
    print("無參多返回值:func5:")
    return true, false, 1, "小明"
end

--有參多返回值
func6 = function(a, b)
    print("有參多返回值:func6:", a, b)
    return true, false, 1, "小明"
end

print(開始執行CSharpCallLuaFunction.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class CSharpCallLuaFunction : MonoBehaviour {
    private LuaEnv luaEnv = new LuaEnv();
    //映射無參無返回值
    [CSharpCallLua]//加特性自動適配,不用再去做映射,效率高
    private delegate void Func1();
    //映射有參無返回值  參數可以是任意類型
    [CSharpCallLua]
    private delegate void Func2(string a, int b);
    //無參有返回值   最好委托返回值類型與lua中方法的返回值相對應
    [CSharpCallLua]
    private delegate int Func3();
    [CSharpCallLua]
    private delegate void Func4();
    //無參多返回值
    [CSharpCallLua]
    private delegate bool Func5(out bool outOne, ref int outTwo, out string outThree);
    //有參多返回值
    [CSharpCallLua]
    private delegate bool Func6(int a, out bool outOne, int b);
    // Use this for initialization
    void Start () {
        luaEnv.DoString("require‘CSharpCallLuaFunction‘");
        //全局的方法依舊存儲在 Global中
        //1. 全局方法映射到委托
        Func1 func1 = luaEnv.Global.Get<Func1>("func1");
        func1();
        // 對於Lua中任意的方法,C#任意的一個委托類型都能映射過來,
        // 只是對於返回值和參數的情況會忽略處理
        // 最好使用相對應的委托去映射
        //Del func2 = luaenv.Global.Get<Del>("func6");
        // func2();
        Func2 func2 = luaEnv.Global.Get<Func2>("func2");
        func2("小明", 81);
        Func3 func3 = luaEnv.Global.Get<Func3>("func3");
        Debug.Log("func3的返回值" + func3());
        Func5 func5 = luaEnv.Global.Get<Func5>("func5");
        bool outOne = false;
        int outTwo = 0;
        string outThree ="";
        bool rt = func5(out outOne, ref outTwo, out outThree);
        Debug.Log("func5:第1個返回值:" + rt + "第2個返回值:" + outOne + "第3個返回值:" + outTwo + "第4個返回值:" + outThree);
        Func6 func6 = luaEnv.Global.Get<Func6>("func6");
        bool out1;
        bool rt1 = func6(3, out out1, 4);
        Debug.Log(rt1 + "------" + out1);


        //2. LuaFunction映射,效率低
        LuaFunction luaFunc6 = luaEnv.Global.Get<LuaFunction>("func6");
        //調用方法  參數就是方法的參數,返回值就是lua方法的返回值,多返回值存入數組中
        object[] obj_Arr = luaFunc6.Call(1, 2);
        foreach (var item in obj_Arr)
        {
            Debug.Log(item);
        }
    }
       
       // Update is called once per frame
       void Update () {
              
       }
    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}
Lua調用C#的變量或方法 調用靜態的變量:CS.命名空間.類名.變量或屬性名 或 CS.類名.變量或屬性名 調用成員的變量: 1、類實例化:變量名 = CS.命名空間.類名() 或 CS.類名() 2、調用成員變量或屬性:對象名.變量名或屬性名 Lua調用C#的方法 靜態:調用C#的靜態方法: CS.命名空間.類名.方法名() 或 CS.類名.方法名() 非靜態的: 調用C#的成員方法: 對象名:方法名() NewGameObject.lua.txt
print(開始執行NewGameObject.lua)
--C#:GameObject obj = new UnityEngine.GameObject();
--實例化一個對象
obj = CS.UnityEngine.GameObject();
print(結束執行NewGameObject.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class NewGameObject : MonoBehaviour {


    private LuaEnv luaEnv = new LuaEnv();


    void Start () {
        luaEnv.DoString("require ‘NewGameObject‘ ");
        //GameObject obj = new UnityEngine.GameObject();
    }


    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}

LuaCallCSharpVariate.lua.txt

print(開始執行LuaCallCSharpVariate.lua)
--靜態變量:CS.命名空間.類名.變量或屬性名 或 CS.類名.變量或屬性名
print("A靜態變量", CS.Lesson.A.name)
--調用成員變量,首先需要new出來對象
a = CS.Lesson.A()
--調用成員變量:對象名.變量名或屬性名
print("A成員變量", a.id, a.Sex)
print(結束執行LuaCallCSharpVariate.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaCallCSharpVariate : MonoBehaviour {


    private LuaEnv luaEnv = new LuaEnv();


    void Start()
    {
        luaEnv.DoString("require ‘LuaCallCSharpVariate‘ ");     
    }


    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}


namespace Lesson
{
    public class A
    {
        public static string name = "A";
        public int id;
        private bool sex;
        public bool Sex
        {
            get { return sex; }
            set { sex = value; }
        }
        public A() { id = 1; sex = true; }
    }
}

LuaCallCSharpFunction.lua.txt

print(開始執行LuaCallCSharpFunction.lua)

--C# B.StaticFunc()

--調用C#的靜態方法:CS.命名空間.類名.方法名() 或 CS.類名.方法名()
CS.Lesson.B.StaticFunc()

--調用C#的成員方法
--實例化一個類對象
b = CS.Lesson.B()

--調用C#的成員方法:對象名:方法名()
b:UnStaticFunc()

--Xlua支持通過子類的對象去訪問父類的方法、屬性、變量
b:Func()

print(結束執行LuaCallCSharpFunction.lua)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class LuaCallCSharpFunction : MonoBehaviour {

    private LuaEnv luaEnv = new LuaEnv();

    void Start()
    {
        luaEnv.DoString("require ‘LuaCallCSharpFunction‘ ");
    }

    void Update()
    {
    }
    private void OnDestroy()
    {
        luaEnv.Dispose();
    }
}

namespace Lesson
{
    public class B : C
    {
        public static void StaticFunc()
        {
            Debug.Log("這是一個靜態方法");
        }
        public void UnStaticFunc()
        {
            Debug.Log("這是一個非靜態方法");
        }
    }
    public class C
    {
        public void Func()
        {
            Debug.Log("Func");
        }
    }
}
案例 - 用Lua實現遊戲物體旋轉移動 Move.lua.txt
print("開始執行Move")

--參數就是Move的類對象
Set = function(self)
    move = self
end

Update = function()
    --C# transform.Rotate(Vector3.up*30 * Time.deltaTime);
    print("Update")

    move.transform:Rotate(CS.UnityEngine.Vector3.up * 30 * CS.UnityEngine.Time.deltaTime);

    v = CS.UnityEngine.Input.GetAxis("Vertical");
    h = CS.UnityEngine.Input.GetAxis("Horizontal");

    move.transform:Translate(CS.UnityEngine.Vector3(h,0,v) * CS.UnityEngine.Time.deltaTime);

end

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
public class Move : MonoBehaviour
{
    private LuaEnv luaenv = new LuaEnv();


    [CSharpCallLua]
    private delegate void Del();
    [CSharpCallLua]
    private delegate void Set(Move move);
    private Del update;

    void Start()
    {
        luaenv.DoString("require ‘Move‘");
        Set set = luaenv.Global.Get<Set>("Set");
        set(this);//把自己傳遞到lua中去
        update = luaenv.Global.Get<Del>("Update");
    }

    void Update()
    {
        //transform.Rotate(Vector3.up*30 * Time.deltaTime);
        //transform
        /*
        float v = Input.GetAxis("Vertical");
        float h = Input.GetAxis("Horizontal");
        transform.Translate(new Vector3(h,0,v) * Time.deltaTime);
        */
        if (null != update)
        {
            update();
        }
    }


    private void OnDestroy()
    {
        update = null;
        luaenv.Dispose();
    }
}

Unity3D學習筆記(三十一):Xlua(1)