xlua 學習教程 XLua 學習筆記記錄

 untiy 學習討論羣 184386599

1:直接去官網下載 https://github.com/Tencent/xLua

下載解壓文件

2:創建一個Unity空項目

3:選擇 xlua-》Assets 下的plugins +xlua 文件 放到Unity工程Assets下

直接代碼了:裏面有全部的註釋和遇到的一些問題,有些問題也還不知道原因,可能是版本不兼容先記錄一下

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;  //引入命名空間

public class Test : MonoBehaviour
{
    LuaEnv luaEnv;  //lua虛擬機 來運行lua 代碼
    // Start is called before the first frame update
    void Start()
    {
        luaEnv = new LuaEnv();
        //LoadLua_1();
        //LoadLua_2();
        //LoadLua_3();
        //CSCallLua();

        LuaCallCSharp();
    }

    /// <summary>
    /// 第一種加載lua 代碼方式 不建議使用
    /// </summary>
    public void LoadLua_1()
    {
        luaEnv.DoString("print('hello World Lua')");  //輸出
        //luaEnv.DoString("print('hello World Lua2222')");  //輸出
    }

    /// <summary>
    /// 第二種加載lua 代碼方式 建議使用
    /// 先創建一個 testlua.lua 文件
    /// </summary>
    public void LoadLua_2()
    {
        //Resources 根據文件類型自動加載文件後綴, 這個就變成了 testlua.txt 所以這樣寫會加載不出來
        //所以要把這個文件區分是lua文件就要再加個後綴 testlua.lua.txt
        //TextAsset textAsset = Resources.Load<TextAsset>("testlua.lua");
        //luaEnv.DoString(textAsset.ToString());

        //這種方式使用  mylua.lua.txt 必須是這個後綴  require 引入並執行文件裏面的代碼
        //require實際上是調一個個的loader去加載,有一個成功就不再往下嘗試,全失敗則報文件找不到。
        //目前xLua除了原生的loader外,還添加了從Resource加載的loader,需要注意的是因爲Resource只支持有限的後綴
        //放Resources下的lua文件得加上txt後綴  
        luaEnv.DoString("require 'myLua'");
       //這個loader 只能從Resoruce 裏面加載lua文件 

    }

    /// <summary>
    /// 加載lua文件 自定義loader
    /// </summary>
    public void LoadLua_3()
    {
        luaEnv.AddLoader(OurSetLoder); //添加加載lua 文件的loader
        luaEnv.DoString("require 'test'");
    }

    /// <summary>
    /// 自定義的 loader 當lua 虛擬機添加了自定義的loader 時會先執行這個自定義的loader 
    /// </summary>
    /// <param name="filePath"></param>
    /// <returns></returns>
    private byte[] OurSetLoder(ref string filePath)
    {
        Debug.Log("OurSetLoder--- fliePath = " + filePath);

        //在這個地方就可以對自己的代碼做加密解密的工作


        //這是一段lua代碼 需要轉成byte 文件
        //string str = "print('測試自定義loader')";
        //return System.Text.Encoding.UTF8.GetBytes(str);


        //通過自定義的文件目錄來加載lua文件  lua存放路徑
        string luaPath = Application.dataPath + "/lua/"+ filePath+ ".lua.txt";
        byte[] tempBytes = System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(luaPath));

        return tempBytes;
    }

    /// <summary>
    /// 訪問lua 文件定義的變量-------------------------------------------------------------------------------------------------
    /// </summary>
    public void CSCallLua()
    {
        //lua虛擬機編譯lua 文件
        LoadLua_3();
        //CSCallLuaGlobalVal();
        CSCallLuaTable();

    }

    /// <summary>
    /// C#訪問lua 全局變量
    /// </summary>
    public void CSCallLuaGlobalVal()
    {
        //注意 類型, 和變量名 要對應  lua number 對應 C# int float double 
        int hp = luaEnv.Global.Get<int>("hp");
        float mp = luaEnv.Global.Get<float>("mp");
        string name = luaEnv.Global.Get<string>("name");
        bool canFly = luaEnv.Global.Get<bool>("canFly");
        Debug.Log("hp = " + hp + "  mp = " + mp + "  name = " + name + "  canFly = " + canFly);
    }


    //對應lua HeroTable 的類 屬性也可不不讀取完 但是必須對應  對應的屬性name hp 必須是public 
    public class Hero
    {
        public string name;
        public int hp ;
        public Skills[] skills;

        public void PrintSkills()
        {
            if (skills.Length == 0)
            {
                Debug.LogError("沒有讀取到數組");
                return;
            } 

            for (int i=0; i< skills.Length;i++)
            {
                Debug.Log("name = "+ skills[i].name + " hart" + skills[i].hart + " cd" + skills[i].cd);
            }
        }
        public string GetName()
        {
            return name;
        }
        public int GetHp()
        {
            return hp;
        }
    }
    //對應lua SkillTable 的類
    public class Skills
    {
        public string name;
        public int hart ;
        public int cd ;
    }

    //使用接口 ----------------  必須加這個[CSharpCallLua]  untiy 2018不兼容 只有2017才行 
    [CSharpCallLua]
    public interface IHero
    {
        string name { get; set; }
        int hp { get; set;}
        Skills[] skills { get; set; }
    }

    [CSharpCallLua]
    public interface ISkills
    {
        string name { get; set; }
        int hart { get; set; }
        int cd { get; set; }
    }

    /// <summary>
    /// C# 訪問lua table 
    /// </summary>
    public void CSCallLuaTable()
    {
        // 1、映射到普通class或struct 定義一個class,有對應於table的字段的public屬性,而且有無參數構造函數都可以
        //這種方式下xLua會幫你new一個實例,並把對應的字段賦值過去。
        //table的屬性可以多於或者少於class的屬性。可以嵌套其它複雜類型。
        //要注意的是,這個過程是值拷貝,如果class比較複雜代價會比較大。而且修改class的字段值不會同步到table,反過來也不會

        //Hero hero = luaEnv.Global.Get<Hero>("Hero");
        //Debug.Log("hero.name = " + hero.GetName() + "   hero.hp = " + hero.GetHp());
        //hero.PrintSkills();

        //2、映射到一個interface 這種方式依賴於生成代碼(如果沒生成代碼會拋InvalidCastException異常),-------------
        //代碼生成器會生成這個interface的實例,如果get一個屬性,生成代碼會get對應的table字段,
        //如果set屬性也會設置對應的字段。甚至可以通過interface的方法訪問lua的函數
        //接口是一個引用拷貝 在接口裏面改變了 lua 變量 lua 變量原始值也會改變

        //接口需要測試,2018 不兼容一直報錯(需要清理然後重新生成一下代碼)  推薦使用的事這種方式
        //IHero hero = luaEnv.Global.Get<IHero>("Hero");
        //Debug.Log("hero.name = " + hero.name + "   hero.hp = " + hero.hp);
        //if (hero.skills.Length == 0)
        //{
        //    Debug.LogError("沒有讀取到數組");
        //    return;
        //}
        //for (int i = 0; i < hero.skills.Length; i++)
        //{
        //    Debug.Log("IHero name = " + hero.skills[i].name + " IHerohart" + hero.skills[i].hart + " IHerocd" + hero.skills[i].cd);
        //}

        //3.通過Dictionary 來映射  只能拿到有 table 裏面有key 的鍵值對 {3,4,5} 這種拿不到
        //Dictionary<string, object> dic = luaEnv.Global.Get<Dictionary<string, object>>("Hero");
        //foreach (string key in dic.Keys)
        //{
        //    Debug.Log("key = " + key + "  value = " + dic[key]);
        //}

        //4.通過list 來映射 list 只能映射{3,4,5}裏面的值 不能映射table有key的值
        //List<object> list = luaEnv.Global.Get<List<object>>("Hero");
        //foreach (object obj in list)
        //{
        //    Debug.Log("obj = " + obj);
        //}

        //5.通過luatable  xlua自定義 好像也只能得到帶key 值的數據
        //LuaTable luaTab = luaEnv.Global.Get<LuaTable>("Hero");
        //Debug.Log("name = "+ luaTab.Get<string>("name") + "  hp= "+ luaTab.Get<string>("hp"));


        //訪問lua 裏面的全局函數
        //不帶參數的函數
        //Action act = luaEnv.Global.Get<Action>("CallLua");
        //act();
        //act = null; //這個被lua虛擬機引用 清空才能dipose lua虛擬機

        ////帶參數的函數 1 也需要生成代碼
        //Action<int,int> act1 = luaEnv.Global.Get<Action<int,int>>("CallLua");
        //act1(1,2);
        //act1 = null;

        //通過定義委託類型
        //CallLua callLua = luaEnv.Global.Get<CallLua>("CallLua");
        //callLua(3, 4);
        //callLua = null;

        ////有返回值 這個總是報錯也不知道咋回事 也重新生成代碼了還是不行 ref 也可以
        //CallLuaAdd callLuaAdd = luaEnv.Global.Get<CallLuaAdd>("CallLuaAdd");
        //int num = callLuaAdd(3, 4);
        //Debug.Log("num =  " + num);
        //callLuaAdd = null;

        //多個返回值依次類推 這個總是報錯也不知道咋回事
        //CallLuaAdd1 callLuaAdd1 = luaEnv.Global.Get<CallLuaAdd1>("CallLuaAdd1");
        //int resa;
        //int resb;
        //int num = callLuaAdd1(3, 4,out resa,out resb);
        //Debug.Log("num =  " + num+ "resa =  " + resa + "resb =  " + resb);
        //callLuaAdd1 = null;

        //通過luaFuntion 多參數返回 不建議使用 性能慢
        LuaFunction luaFun = luaEnv.Global.Get<LuaFunction>("CallLuaAdd1");
        object[] objs = luaFun.Call(6, 7);
        foreach (object o in objs)
        {
            Debug.Log("xxxx-----o = "+ o);
        }

    }

    //定義委託和 lua裏面函數名一樣 並且加上CSharpCallLua 標籤
    [CSharpCallLua]
    delegate void CallLua(int a, int b);
    //有返回值
    [CSharpCallLua]
    delegate int CallLuaAdd(int a, int b);
    //多個返回參數
    [CSharpCallLua]
    delegate int CallLuaAdd1(int a, int b, out int resa, out int resb);

    /// 訪問lua 文件定義的變量-------------------------------------------------------------------------------------------------


    /// <summary>
    /// lua 調用C#
    /// </summary>
    public void LuaCallCSharp()
    {
        luaEnv.AddLoader(OurSetLoder); //添加加載lua 文件的loader
        luaEnv.DoString("require 'luaCallCSharp'");

        //local newObj = CS.UnityEngine.GameObject("Cube") CS開頭

        //靜態屬性通過類訪問
        // CS.UnityEngine.Time.deltaTime   CS.UnityEngine.Time.timeScale = 0.5  
        //小技巧:如果需要經常訪問的類,可以先用局部變量引用後訪問,除了減少敲代碼的時間,還能提高性能:
        //local GameObject = CS.UnityEngine.GameObject
        //GameObject.Find('helloworld')

        //訪問C#成員屬性,方法
        //直接 Gameobjec.name  
        //.funcName(類對象,參數) 第一個參數默認對象本身  :funcName(參數)


    }
    /// <summary>
    /// 
    /// </summary>
    private void OnDestroy()
    {
        luaEnv.Dispose(); //釋放虛擬機 GC 等
    }
}

對應的lua 文件 自定義文件夾的文件 test.lua.txt 

print("通過lua文件加載test--------- hello world xLua");
hp = 1000
mp = 100.5
name = "哪吒"
canFly = true

print("C#讀取lua的table")

Hero ={
	name = "孫悟空",
	hp = 200000,
	skills = 
	{
	 {
		name = "寒冰掌",
		hart = 100,
		cd = 3
	 },
	  {
		name = "火雲拳",
		hart = 110,
		cd = 4
	 }
	},
	1,2
}

function CallLua()
print("Hero :CallLua")
end

function CallLua(a,b)
print("Hero :CallLua"..a .." b= "..b);
end

function CallLuaAdd(a,b)
	return a+b;
end

function CallLuaAdd1(a,b)
	return a+b,a,b;
end



--默認帶一個self參數代表當前表
function Hero:Talk(str)
print("Hero :Talk str= "..str)
end

--第一個參數要傳遞表
function Hero:TalkOne(self,str)
print("Hero .TalkOne str= " .. str)
end

luaCallCSharp.lua.txt 這個文件裏面只有一句代碼其他可以自己隨便添加: local newObj = CS.UnityEngine.GameObject("Cube")

Resources 文件夾下的lua文件 只有一句輸出

 

untiy 學習討論羣 184386599

發佈了53 篇原創文章 · 獲贊 30 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章