当前位置: 首页 > news >正文

热更新解决方案3 —— xLua

概述

xLua框架导入和AB包相关准备

xLua导入

其它的导入

C#调用Lua

1.Lua解析器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//引用命名空间
using XLua;public class Lesson1_LuaEnv : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){//Lua解析器 能够让我们在Unity中执行Lua//一般情况下 保存它的唯一性LuaEnv env = new LuaEnv();//执行Lua语言//第二个参数是 如果lua出错 会打印第二个参数env.DoString("print('Hello world')", "Lesson1_LuaEnv");//通常我们会执行一个Lua脚本,将要执行的多行代码放入脚本中(Lua知识点:多脚本执行 require)//默认寻找脚本的路径 是在 Resources下 并且 因为在这里估计是通过 Resources.Load去加载Lua脚本的//所以只支持 txt、bytes等文件名后缀,只能在Lua脚本后缀再加上 txt才能执行env.DoString("require('Main')");//帮助我们清除Lua中我们没有手动释放的对象 垃圾回收//帧更新中定时执行 或者 切场景时执行env.Tick();//销毁Lua解析器//通常只会用一个解析器 所以这个函数用的比较少env.Dispose();}// Update is called once per framevoid Update(){}
}

2.Lua文件加载重定向

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;public class Lesson2_Loader : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaEnv env = new LuaEnv();//xlua提供的一个 路径重定向 的方法//允许我们自定义 加载 Lua文件的规则//当我们执行Lua语言 require 时 相当于执行一个lua脚本//它就会 执行 我们自定义传入的这个函数env.AddLoader(MyCustomLoader);//最终我们其实 会去AB包中加载 lua文件env.DoString("require('Main')");env.DoString("require('ttt')");  //测试找不到时 会不会打印我们设置好的错误信息}// Update is called once per framevoid Update(){}//自动执行private byte[] MyCustomLoader(ref string filePath){//通过函数中的逻辑 去加载 Lua文件//传入的参数是 require执行的lua脚本文件名//拼接一个lua文件所在路径string path = Application.dataPath + "/Lua/" + filePath + ".lua";Debug.Log(path);//有路径 就去加载文件 //File 知识点 C#提供的文件读写的类//判断文件是否存在if (File.Exists(path)){return File.ReadAllBytes(path);   //这个方法会将文件中的数据转为二进制数组}return null;}
}

3.Lua解析器管理器

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;/// <summary>
/// Lua管理器
/// 提供 lua解析器
/// 保证解析器的唯一性
/// </summary>
public class LuaMgr : BaseManager<LuaMgr>
{//执行Lua语言的函数//释放垃圾//销毁//重定向private LuaEnv luaEnv;/// <summary>/// 得到Lua 中的_G   后面会频繁使用到/// </summary>public LuaTable Global{get{return luaEnv.Global;}}/// <summary>/// 初始化解析器/// </summary>public void Init(){//若已经初始化了 就直接returnif (luaEnv != null)return;//初始化luaEnv = new LuaEnv();//加载lua脚本 重定向luaEnv.AddLoader(MyCustomLoader);luaEnv.AddLoader(MyCustomABLoader);  // 会依次执行}//Lua脚本会放在AB包//最终我们会通过加载AB包再加载其中的Lua脚本资源 来执行它//AB包中如果加载文本 后缀还是有一定限制的 .lua还是不能被识别//打包时 要把lua文件后缀改为 txt//自动执行private byte[] MyCustomLoader(ref string filePath){//通过函数中的逻辑 去加载 Lua文件//传入的参数 是 require 执行的lua脚本文件名//拼接一个Lua文件所在路径string path = Application.dataPath + "/Lua/" + filePath + ".lua";//有路径 就去加载文件//File知识点 C#提供的文件读写的类//判断文件是否存在if (File.Exists(path))return File.ReadAllBytes(path);elseDebug.Log("MyCustomLoader重定向失败,文件名为:" + filePath);return null;}//重定向加载AB包的Lua脚本private byte[] MyCustomABLoader(ref string filePath){//Debug.Log("进入AB包加载 重定向函数");从AB包中加载lua文件加载AB包//string path = Application.streamingAssetsPath + "/lua";//AssetBundle ab = AssetBundle.LoadFromFile(path);加载Lua文件 返回//TextAsset tx = ab.LoadAsset<TextAsset>(filePath + ".lua");  //改变了文件名所以.lua也是文件名的一部分加载Lua文件 byte数组//return tx.bytes;string path = Application.streamingAssetsPath + "/lua";TextAsset lua = ABMgr.GetInstance().LoadRes<TextAsset>("lua", filePath + ".lua");if (lua != null)return lua.bytes;elseDebug.Log("MyCustomABLoader重定向失败,文件名为:" + filePath);return null;}/// <summary>/// 传入lua文件名 就可以执行luo脚本 (就是DoString 的优化)/// </summary>/// <param name="fileName"></param>public void DoLuaFile(string fileName){string str = string.Format("require('{0}')", fileName);DoString(str);}/// <summary>/// 执行Lua语言/// </summary>/// <param name="str"></param>public void DoString(string str){if(luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.DoString(str);}/// <summary>/// 释放资源/// </summary>public void Tick(){if (luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.Tick();}/// <summary>/// 销毁解析器/// </summary>public void Dispose(){if (luaEnv == null){Debug.Log("解析器未初始化");return;}luaEnv.Dispose();luaEnv = null;}}

测试

4.全局变量获取

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson4_CallVariable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//我们通过C# 没办法直接获取本地局部变量int local = LuaMgr.GetInstance().Global.Get<int>("testLocal");Debug.Log("testLocal:" + local);//使用lua解析器luaenv中的 Global属性int i = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i);i = 10;//值copy 不会影响原来Lua中的值int i2 = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i2);//改值LuaMgr.GetInstance().Global.Set("testNumber", 55);i2 = LuaMgr.GetInstance().Global.Get<int>("testNumber");Debug.Log("testNumber:" + i2);bool b = LuaMgr.GetInstance().Global.Get<bool>("testBool");Debug.Log("testBool:" + b);float f = LuaMgr.GetInstance().Global.Get<float>("testFloat");Debug.Log("testFloat:" + f);double d = LuaMgr.GetInstance().Global.Get<double>("testFloat");Debug.Log("testFloat_Double:" + d);string str = LuaMgr.GetInstance().Global.Get<string>("testString");Debug.Log("testString:" + str);}// Update is called once per framevoid Update(){}
}

5.全局函数获取

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;public class Lesson5_CollFunction : MonoBehaviour
{//无参无返回值的委托public delegate void CustomCall();//有参有返回的委托//该特性是在XLua命名空间中的//加了过后 要在编辑器里 生成 Lua代码[CSharpCallLua]public delegate int CustomCall2(int a);//多返回值委托[CSharpCallLua]public delegate int CustomCall3(int a, out int b, out bool c, out string d, out int e);[CSharpCallLua]public delegate int CustomCall4(int a, ref int b, ref bool c, ref string d, ref int e);//变长参数委托//变长参数的类型 是根据实际情况来定的 如果想要什么类型都接就传 obj[CSharpCallLua]public delegate void CustomCall5(string a, params int[] args);// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//无参无返回的获取//用什么来接收他们呢 —— 委托最合适CustomCall call = LuaMgr.GetInstance().Global.Get<CustomCall>("testFun");call();//Unity自带委托UnityAction ua = LuaMgr.GetInstance().Global.Get<UnityAction>("testFun");ua();//C#提供的委托Action ac = LuaMgr.GetInstance().Global.Get<Action>("testFun");ac();//XLua提供的一种 获取函数的方法 (尽量少用)LuaFunction lf = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun");lf.Call();//有参有返回CustomCall2 call2 = LuaMgr.GetInstance().Global.Get<CustomCall2>("testFun2");Debug.Log("有参有返回:" + call2(10));//C#自带的泛型委托 (一般情况下我们都不会自己去申明委托,基本上都是有C#或Unity自带的委托)Func<int, int> sFun = LuaMgr.GetInstance().Global.Get<Func<int, int>>("testFun2");Debug.Log("有参有返回值:" + sFun(20));//XLua提供的LuaFunction lf2 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun2");Debug.Log("有参有返回值:" + lf2.Call(30)[0]);//多返回值//使用out 和 ref 来接收  (out外面不需要初始化)//outCustomCall3 call3 = LuaMgr.GetInstance().Global.Get<CustomCall3>("testFun3");int b;bool c;string d;int e;Debug.Log("第一个返回值:" + call3(100, out b, out c, out d, out e));Debug.Log(b + "_" + c + "_" + d + "_" + e);//refCustomCall4 call4 = LuaMgr.GetInstance().Global.Get<CustomCall4>("testFun3");int b1 = 0;bool c1 = true;string d1 = "";int e1 = 0;Debug.Log("第一个返回值:" + call4(200, ref b1, ref c1, ref d1, ref e1));Debug.Log(b1 + "_" + c1 + "_" + d1 + "_" + e1);//XLua    (用于多返回值比较适用, 但是会产生垃圾,所以不是很建议使用)LuaFunction lf3 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun3");object[] objs = lf3.Call(1000);for (int i = 0; i < objs.Length; i++){Debug.Log("第" + i + "个返回值是: " + objs[i]);}//变长参数CustomCall5 call5 = LuaMgr.GetInstance().Global.Get<CustomCall5>("testFun4");call5("123", 1, 2, 3, 4, 5, 5, 66, 666);//XLuaLuaFunction lf4 = LuaMgr.GetInstance().Global.Get<LuaFunction>("testFun4");lf4.Call("456", 5, 6, 7, 99);}// Update is called once per framevoid Update(){}
}

6.映射到List和Dictionary

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Lesson6_CollListDic : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//同一类型ListList<int> list = LuaMgr.GetInstance().Global.Get<List<int>>("testList");Debug.Log("**********list**************");for (int i = 0; i < list.Count; i++){Debug.Log(list[i]);}//值拷贝(浅拷贝) 不会改变lua中的内容list[0] = 100;List<int> list2 = LuaMgr.GetInstance().Global.Get<List<int>>("testList");Debug.Log(list[0]);//不指定类型的话 就用objectList<object> list3 = LuaMgr.GetInstance().Global.Get<List<object>>("testList2");Debug.Log("*********list object***************");for (int i = 0; i < list3.Count; i++){Debug.Log(list3[i]);}Debug.Log("*********Dictionary***************");Dictionary<string, int> dic = LuaMgr.GetInstance().Global.Get<Dictionary<string, int>>("testDic");foreach (string item in dic.Keys){Debug.Log(item + "_" + dic[item]);}//检测是不是 值拷贝  —— 还是值拷贝dic["1"] = 10000;Dictionary<string, int> dic2 = LuaMgr.GetInstance().Global.Get<Dictionary<string, int>>("testDic");Debug.Log(dic2["1"]);//不指定类型 还是用 objectDebug.Log("*********Dictionary***************");Dictionary<object, object> dic3 = LuaMgr.GetInstance().Global.Get<Dictionary<object, object>>("testDic2");foreach (object item in dic3.Keys){Debug.Log(item + "_" + dic3[item]);}}// Update is called once per framevoid Update(){}
}

7.映射到类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;public class CallLuaClass
{//在这个类中去声明成员变量//名字一定要和 Lua那么的一样//要公共的  (私有和保护的 没办法赋值)//这个自定义中的 变量 可以更多也可以更少//如果变量比 lua中的少 就会忽略它//如果多了 不会赋值 也相当于忽略public int testInt;public bool testBool;//public float testFloat;public string testString;public int i;public UnityAction testFun;public CallLuaInClass testInClass;
}public class CallLuaInClass
{public int testInInt;
}public class Lesson7_CallClass : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");CallLuaClass obj = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");Debug.Log(obj.testInt);Debug.Log(obj.testBool);//Debug.Log(obj.testFloat);Debug.Log(obj.testString);Debug.Log(obj.i);Debug.Log("嵌套里的:" + obj.testInClass.testInInt);obj.testFun();//测试 是否是值拷贝//值拷贝 改变它 不会改变Lua表里的内容obj.testInt = 100;CallLuaClass obj2 = LuaMgr.GetInstance().Global.Get<CallLuaClass>("testClass");Debug.Log(obj2.testInt);}// Update is called once per framevoid Update(){}
}

8.映射到接口

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;//接口中是不允许有成员变量的 但是可以有属性
//我们可以用属性来接收
//接口和类规则一样 其中的属性多了少了 不影响结果 无非就是忽略
//嵌套几乎和类一样 无非 是要遵循接口的规则
[CSharpCallLua]
public interface ICSharpCallInterface
{int testInt{get;set;}bool testBool{get;set;}//float testFloat//{//    get;//    set;//}string testString{get;set;}UnityAction testFun{get;set;}float testFloat22{get;set;}
}public class Lesson8_CallInterface : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");ICSharpCallInterface obj = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass");Debug.Log(obj.testInt);Debug.Log(obj.testBool);Debug.Log("新加的:" + obj.testFloat22);Debug.Log(obj.testString);obj.testFun();//测试 是否 值拷贝//接口拷贝 是引用拷贝 改了值 lua表中的值也变了obj.testInt = 1000;ICSharpCallInterface obj2 = LuaMgr.GetInstance().Global.Get<ICSharpCallInterface>("testClass");Debug.Log(obj2.testInt);  // 1000}// Update is called once per framevoid Update(){}
}

9.映射到LuaTable

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using XLua;public class Lesson9_CallLuaTable : MonoBehaviour
{// Start is called before the first frame updatevoid Start(){LuaMgr.GetInstance().Init();LuaMgr.GetInstance().DoLuaFile("Main");//官方不建议使用LuaTable 和 LuaFunction  因为效率低 并且会产生垃圾//引用对象LuaTable table = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table.Get<int>("testInt"));Debug.Log(table.Get<bool>("testBool"));Debug.Log(table.Get<float>("testFloat"));Debug.Log(table.Get<string>("testString"));table.Get<LuaFunction>("testFun").Call();//引用拷贝table.Set("testInt", 55);LuaTable table2 = LuaMgr.GetInstance().Global.Get<LuaTable>("testClass");Debug.Log(table2.Get<int>("testInt"));//用完 table 记得要 清除它 不然会产生垃圾table.Dispose();table2.Dispose();}// Update is called once per framevoid Update(){}
}

10.CSharpCallLua特性什么时候用

Lua调用C#

1.类

print("************Lua 调用 C#类相关知识点************")--lua中使用C#的类非常简单
--固定套路:
--CS.命名空间.类名
--Unity的类 比如 GameObject Transform等等 —— CS.UnityEngine.类名
--CS.UnityEngine.GameObject--通过C#中的类 实例化一个对象 lua中没有new 所以我们直接 类名括号就是实例化对象
--默认调用的 相当于就是无参构造
local obj1 = CS.UnityEngine.GameObject()
local obj1 = CS.UnityEngine.GameObject("Sunset")  --带传参--为了方便使用 并且节约性能 定义全局变量存储 C#中的类
--这样定义 相当于是取了一个别名
GameObject = CS.UnityEngine.GameObject
local obj3 = GameObject("山有木兮")--类中的静态对象 可以直接使用 .来调用
local obj4 = GameObject.Find("Sunset")--得到对象中的成员变量 直接对象 . 即可
print(obj4.transform.position)
Debug = CS.UnityEngine.Debug
Debug.Log(obj4.transform.position)Vector3 = CS.UnityEngine.Vector3
--如果使用对象中的 成员方法 !!! 一定要加 冒号 :
obj4.transform:Translate(Vector3.right)
Debug.Log(obj4.transform.position)--自定义类 使用方法 相同 只是命名空间不同而已
local t = CS.Test1()
t:Speak("说话")local t2 = CS.Sunset.Test2()
t2:Speak("说话")--继承了Mono的类
--继承了Mono的类 是不能直接 new
local obj5 = GameObject("加脚本测试")
--通过GameObject的 AddComponent 添加脚本
--xlua提供了一个重要方法 typeof 可以得到类的Type
--xlua中不支持 无参泛型函数 所以 我们要使用另一个重载
obj5:AddComponent(typeof(CS.LuaCallCSharp))

2.枚举

3.数组、List和Dictionary

print("**********Lua调用C# 数组 相关知识点********")-- 实例化出对象
local obj = CS.Lesson3()--Lua使用C#数组相关知识
--长度 userdata
--C#怎么用 lua就怎么用 不能使用#去获取长度
print(obj.array.Length)--访问元素
print(obj.array[0])--遍历要注意 虽然lua中索引从1开始
--但是数组是C#那边的规则 所以 还是按C#的0开始
--注意最大值 一定要减1
for i=0,obj.array.Length-1 doprint(obj.array[i])
end--Lua中创建一个C#的数组 Lua中表示数组和List可以用比表
--但是若要使用C#中???
--创建C#中的数组 使用 Array类中的静态方法即可
--该方法就是创建一个数组,第一个参数是数组类型,第二个参数是数组大小
local array2 = CS.System.Array.CreateInstance(typeof(CS.System.Int32), 10)
print(array2.Length)
print(array2[0])
print(array2[1])
print(array2)print("**********Lua调用C# list 相关知识点********")
--调用成员方法 用冒号
obj.list:Add(1)
obj.list:Add(2)
obj.list:Add(3)
--长度
print(obj.list.Count)
--遍历
for i = 0,obj.list.Count-1 doprint(obj.list[i])
end
print(obj.list)--在Lua中创建一个List对象
--老版本中
local list2 = CS.System.Collections.Generic["List`1[System.String]"]()
print(list2)
list2:Add("123")
print(list2[0])--新版本 > v2.1.12
--相当于得到一个 List<string> 的一个类别名 需要再实例化
local List_String = CS.System.Collections.Generic.List(CS.System.String)
local list3 = List_String()
list3:Add("555555")
print(list3[0])print("**********Lua调用C# Dictionary 相关知识点********")
--使用和C#一致
obj.dic:Add(1, "123")
print(obj.dic[1])--遍历
for k,v in pairs(obj.dic) doprint(k,v)
end--在Lua中创建一个字典对象
--也分老版本和新版本
--这里只讲解 新版本(老版本可以去了解)
local Dic_String_Vector3 = CS.System.Collections.Generic.Dictionary(CS.System.String, CS.UnityEngine.Vector3)
local dic2 = Dic_String_Vector3()
dic2:Add("123",CS.UnityEngine.Vector3.right)
for k,v in pairs(dic2) doprint(k,v)
end
--在Lua中创建的字典 直接通过键中括号得 是得不到 返回的是nil
print(dic2["123"])
--字典里还有一个方法也能够正常得到值
print(dic2:TryGetValue("123"))  -- 返回两个值 true 值
--如果要通过键获取值 要通过这个固定方法
print(dic2:get_Item("123"))
dic2:set_Item("123", nil)
print(dic2:get_Item("123"))

4.函数(拓展方法)

5.函数(ref 和 out)

print("***********Lua调用C# ref 方法相关知识点***********")Lesson5 = CS.Lesson5local obj = Lesson5()--ref参数 会以多返回值的形式返回给lua
--如果函数存在返回值 那么第一个值 就是该返回值
--之后的返回值 就是ref的结果 从左到右一一对应
--ref参数 需要传入一个默认值 占位置
--a 相当于 函数返回值
--b 第一个ref
--c 第二个ref
local a,b,c = obj:RefFun(1, 0, 0, 1)
print(a)
print(b)
print(c)print("***********Lua调用C# out 方法相关知识点***********")
--out参数 也会以多返回值的形式返回给lua
--如果函数存在返回值 那么第一个值 就是该返回值
--之后的返回值 就是out的结果 从左到右一一对应
--out参数 不需要传占位置的值
local a,b,c = obj:OutFun(20, 30)
print(a)
print(b)
print(c)--混合使用时 综合上面的规则
--ref 需要占位  out不用传
--第一个是函数的返回值 之后 从左到右依次对应ref或者out
local a,b,c = obj:RefOutFun(20, 1)  --ref 的占位值不一定要是0,可以用其他数
print(a)  --300
print(b)  --200
print(c)  --400

6.函数(重载)

print("**********Lua调用C# 重载函数相关知识点**********")Lesson6 = CS.Lesson6
local obj = Lesson6()--虽然Lua自己不支持写重载函数
--但是Lua支持调用C#中的重要函数
print(obj:Calc())
print(obj:Calc(15, 1))--Lua虽然支持调用C#重载函数
--但是因为Lua中的数值类型 只有Number
--对C#中多精度的重载函数支持的不好  会傻傻分不清
--在使用时 可能出现意向不到的问题
print(obj:Calc(10))
print(obj:Calc(10.2))--解决重载函数含糊的问题
--xlua提供了解决方案 通过反射机制
--这种方法只做了解 尽量别用 (因为效率低)
--Type是反射的关键类
--得到指定函数的相关信息
local m1 = typeof(CS.Lesson6):GetMethod("Calc", {typeof(CS.System.Int32)})
local m2 = typeof(CS.Lesson6):GetMethod("Calc", {typeof(CS.System.Single)})--通过xlua提供的一个方法 把它转成lua函数来使用
--一般我们转一次 然后重复来使用
local f1 = xlua.tofunction(m1)
local f2 = xlua.tofunction(m2)
--成员方法  第一个参数传对象
--静态方法  不用传对象
print(f1(obj, 10))
print(f2(obj, 10.2))

7.委托和事件

print("**********Lua调用C# 委托 相关知识点********")local obj = CS.Lesson7()--委托是用来装函数的
--使用C#中的委托 就是用来装lua函数的
local fun = function()print("Lua函数Fun")
endprint("********加函数********")
--Lua中没有复合运算符 不能 +=
--如果第一次往委托中加函数 因为是nil 不能直接+
--所以第一次 要先等 +
obj.del = fun
obj.del = obj.del + fun
--不建议这么写 最好还是 先声明函数再加 (因为这个像匿名函数,后面移除会不好找)
obj.del = obj.del + function()print("临时声明的函数")
end
--委托执行
obj.del()print("********减函数********")
obj.del = obj.del - fun
obj.del = obj.del - fun
obj.del()print("********清空函数********")
--第三个函数没有函数名
--只能清空所有存储的函数
obj.del = nil
--清空后得先 等于
obj.del = fun
--调用
obj.del()print("**********Lua调用C# 事件 相关知识点********")
local fun2 = function()print("事件加的函数")
endprint("********事件加函数********")
--事件加减函数 和 委托非常不一样
--Lua中使用C#事件 加函数
--有点类似使用成员方法 冒号 事件名("+", 函数变量)
obj:eventAction("+", fun2)
--最好也不要这么写
obj:eventAction("+", function()print("事件加的匿名函数")
end)
--调用只能在内部给出方法
obj:DoEvent()print("********事件减函数********")
obj:eventAction("-", fun2)
obj:DoEvent()print("********事件清除********")
--请事件 不能直接设空
--因为在C#中事件是不允许在外部等于和调用的
--obj:eventAction = nil
--但是我们可以在这个事件的类的内部写一个清除的方法出来调用
obj:ClearEvent()
obj:DoEvent()

8.特殊问题(二维数组遍历)

9.特殊问题(null和ni比较)

拓展方法记得加特性

10.特殊问题(让系统类型和Lua能相互访问)

11.协程

print("************Lua调用C# 协程 相关知识点**************")
--xlua提供的一个工具表
--一定是要通过require 调用后 才能用
util = require("xlua.util")--C#中协程启动都是通过继承了Mono的类 通过里面的启动函数StartCoroutineGameObject = CS.UnityEngine.GameObject
WaitForSeconds = CS.UnityEngine.WaitForSeconds--在场景中新建一个空物体 然后挂一个脚本上去 脚本继承momo使用它来开启协程
local obj = GameObject("Coroutine")
local mono = obj:AddComponent(typeof(CS.LuaCallCSharp))--希望用来被开启的协程函数
fun = function()local a = 1while true do--lua中 不能直接使用 C#中的 yield return--那就使用lua中的协程返回coroutine.yield(WaitForSeconds(1)) --后面的每隔一秒打印其实就是我们C#的方法print(a)a = a + 1if a > 10 thenmono:StopCoroutine(b)endend
end--我们不能直接将 lua函数传入到C#开启协程中!!!
--mono:StartCoroutine(fun)
--如果要把lua函数当中协程函数传入
--必须 先调用 xlua.util中的 cs_generator(lua函数)
--它的返回值才是一个协程函数
--关闭的话 我们就先存起它来
b = mono:StartCoroutine(util.cs_generator(fun))

12.泛型函数

print("**************Lua调用C# 泛型函数相关知识点***************")local obj = CS.Lesson12()local child = CS.Lesson12.TestChild()
local father = CS.Lesson12.TestFather()--支持有约束有参数的泛型函数
obj:TestFun1(child, fater)
obj:TestFun1(father, child)--lua中不支持 没有约束的泛型函数
--obj:TestFun2(child)  -- 会报错--lua中不支持 有约束 但是没有参数的泛型函数
--obj:TestFun3()--lua中不支持 非class的约束 (如不支持 接口约束)
--obj:TestFun4()--下面的方法有一定的使用限制
--Mono打包 这种方式支持使用
--il2cpp打包 如果泛型参数是引用类型才可以使用
--il2cpp打包 如果泛型参数是值类型,除非C#那边已经调用过了同类型的泛型参数 lua中才能够被使用--补充知识 让上面 不支持使用的泛型函数 变得能用
--得到通用的函数 
--设置泛型类型再使用
--xlua.get_generic_method(类,"函数名")
local testFun2 = xlua.get_generic_method(CS.Lesson12, "TestFun2")
local testFun2_R = testFun2(CS.System.Int32)
--调用
--成员方法 第一个参数 传调用函数的对象
--静态方法 不用传
testFun2_R(obj, 1)

完结:接xLua背包小实践

相关文章:

热更新解决方案3 —— xLua

概述 xLua框架导入和AB包相关准备 xLua导入 其它的导入 C#调用Lua 1.Lua解析器 using System.Collections; using System.Collections.Generic; using UnityEngine; //引用命名空间 using XLua;public class Lesson1_LuaEnv : MonoBehaviour {// Start is called before the fi…...

如何让ai在游戏中更像一个人?

开题开了一整年是我没想到的&#xff0c;还因此延毕了……我重新梳理一下我想做的研究以及相关痕迹。 我2023年3月找到的导师。起初我发现了在玩RTS游戏中会出现很多固定的套路&#xff0c;选手为此要做大量的练习&#xff0c;我就在想如何把这部分内容借助状态机这种流程给…...

websocket_asyncio

WebSocket 和 asyncio 指南 简介 本指南涵盖了使用 Python 中的 websockets 库进行 WebSocket 编程的基础知识&#xff0c;以及 asyncio 在异步非阻塞 I/O 中的作用。它提供了构建高效 WebSocket 服务端和客户端的知识&#xff0c;以及 asyncio 的特性和优势。 1. 什么是 WebS…...

如何在NGINX中实现基于IP的访问控制(IP黑白名单)?

大家好&#xff0c;我是锋哥。今天分享关于【如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f;】面试题。希望对大家有帮助&#xff1b; 如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f; 1000道 互联网大…...

Y3编辑器文档4:触发器1(界面及使用简介、变量作用域、入门案例)

文章目录 一、触发器简介1.1 触发器界面1.2 ECA语句编辑及快捷键1.3 参数设置1.4 变量设置1.5 实体触发器1.6 触发器复用 二、触发器的多层结构2.1 子触发器&#xff08;在游戏内对新的事件进行注册&#xff09;2.2 触发器变量作用域 三、入门案例3.1 使用触发器实现瞬间移动3.…...

echarts图表自定义配置(二)——代码封装

下图是初版&#xff0c;火山图的代码。可以看出&#xff0c;里面的变量&#xff0c;逻辑&#xff0c;函数存在冗余&#xff0c;基本上都是改了参数&#xff0c;同样的get和set&#xff0c;去刷新图表&#xff1b;对于往后继续开发十几二十个图表&#xff0c;会很麻烦。因此需要…...

02、10个富士胶片模拟的设置

二色彩 1、色彩的加减控制全局的饱和度增减&#xff1b; 2、色彩效果只提升暖色系饱和度&#xff1b; 3、FX蓝色大幅度提升蓝色系饱和度&#xff1b; 4、三个参数都不改变颜色的色相。 2.1 色彩 色彩调整的是拍摄画面整体的色彩饱和程度 2.2色彩效果 调整的是画面中暖色…...

鸿蒙系统-前端0帧起手

鸿蒙系统-前端0帧起手 先search 一番 找到对应的入门文档1. 运行项目遇到问题 如下 &#xff08;手动设计npm 的 registry 运行 npm config set registry https://registry.npmjs.org/&#xff09;2.运行后不支持一些模拟器 配置一下&#xff08;如下图&#xff0c;运行成功&am…...

211-基于FMC的1路1.5G ADC 1路 2.5G DAC子卡

一、板卡概述 FMC-1AD-1DA-1SYNC是我司自主研发的一款1路1G AD采集、1路2.5G DA回放的FMC、1路AD同步信号子卡。板卡采用标准FMC子卡架构&#xff0c;可方便地与其他FMC板卡实现高速互联&#xff0c;可广泛用于高频模拟信号采集等领域。 二、功能介绍 2.1 原理框图 2.2 硬件…...

获取微信用户openid

附上开发文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html 开发之前,准备事项 一个已认证过的服务号|基本信息配置js域名和网站授权域名配置最后确认当前账号网页授权功能是否开通,没有开通的无法获取到用户授权开发人…...

MultiRECloudSim使用

MultiRECloudSim使用 简介 MultiRECloudSim是一个用于云计算环境下的模拟器相关工具,它主要用于模拟和评估云计算中的资源分配、任务调度等多种场景。它可能是基于CloudSim这个基础的云计算模拟器进行扩展而来,CloudSim提供了基本的云计算模拟功能,如数据中心、虚拟机、任务…...

智能设备安全-固件逆向分析

固件逆向分析实验报告-20241022 使用固件常用逆向分析工具&#xff0c;对提供的固件进行文件系统提取&#xff0c;并记录逆向分析实验过程&#xff0c;提交实验报告&#xff08;报告要求图文并茂&#xff0c;对涉及到的关键步骤附截图说明&#xff09;。具体任务如下&#xff1…...

【小白包会的】使用supervisor 管理docker内多进程

使用supervisor 管理docker内多进程 一般情况下&#xff0c;一个docker是仅仅运行一个服务的 但是有的情况中&#xff0c;希望一个docker中运行多个进程&#xff0c;运行多个服务&#xff0c;也就是一个docker容器执行多个服务。 调研了一下&#xff0c;发现可以通过**super…...

使用navicat新旧版本,连接PostgreSQL高版本报错问题图文解决办法

使用navicat新旧版本&#xff0c;连接PostgreSQL高版本报错问题图文解决办法 一、问题现象&#xff1a;二、出现原因三、解决方法&#xff1a;1、升级Navicat版本&#xff1a;2、使用低版本的postgreSQL&#xff1a;3、修改Navicat的dll二进制文件&#xff1a;navicat版本15nav…...

IDEA 未启用lombok插件的Bug

项目中maven已引用了lombok依赖&#xff0c;之前运行没有问题的&#xff0c;但有时启动会提示&#xff1a; java: You arent using a compiler supported by lombok, so lombok will not work and has been disabled. Your processor is: com.sun.proxy.$Proxy8 Lombok support…...

认识GO--gRPC的metadata

参考&#xff1a; 写给go开发者的gRPC教程-metadata-CSDN博客https://blog.csdn.net/kevin_tech/article/details/129395177?ops_request_misc%257B%2522request%255Fid%2522%253A%25221f2f2e26f48c755c33344ccb171a49fc%2522%252C%2522scm%2522%253A%252220140713.130102334…...

2024年安徽省职业院校技能大赛信息安全管理与评估

一、赛项名称 赛项名称&#xff1a;信息安全管理与评估 英文名称&#xff1a;Information Security Management and Evaluation 赛项组别&#xff1a;高职组 赛项归属&#xff1a;电子信息大类 二、竞赛目标 通过赛项检验参赛选手熟悉信息安全行业标准规范和信息 安全测试员新职…...

Perl 引用

Perl 引用 Perl&#xff0c;作为一种灵活而强大的编程语言&#xff0c;广泛用于系统管理、网络编程、GUI开发等领域。在Perl编程中&#xff0c;引用&#xff08;References&#xff09;是一个核心概念&#xff0c;它允许变量引用其他数据&#xff0c;从而创建复杂的数据结构&a…...

RT-Thread启动过程 :从汇编开始的启动流程

这个系列参考了《嵌入式实时操作系统RT-Thread设计与实现》&#xff0c;会详细介绍RT-Thread的启动流程&#xff0c;即是如何从零开始在开发板上运行起一个RTOS内核的。本文将会以 ch32v307VCT6 开发板为例展开进行详细介绍。主要包括&#xff1a;startup.S、初始化与系统相关的…...

Scala—“==“和“equals“用法(附与Java对比)

Scala 字符串比较—""和"equals"用法 Scala 的 在 Scala 中&#xff0c; 是一个方法调用&#xff0c;实际上等价于调用 equals 方法。不仅适用于字符串&#xff0c;还可以用于任何类型&#xff0c;并且自动处理 null。 Demo&#xff1a; Java 的 在 J…...

$route和$router的区别

在 Vue.js 中&#xff0c;$route 和 $router 都是 Vue Router 提供的对象&#xff0c;但它们有不同的用途和功能。 1. $router $router 是 Vue Router 实例的引用&#xff0c;它允许你通过 JavaScript 进行路由的控制和导航。你可以通过 $router 来执行路由的操作&#xff0c…...

[工具升级问题] 钉钉(linux版)升级带来的小麻烦

本文由Markdown语法编辑器编辑完成。 1. 背景: 今日钉钉又发布了新的升级版本。由于我工作时使用的是Ubuntu 20.04版本&#xff0c;收到的升级推送信息是&#xff0c;可以升级到最新的7.6.25-Release版本。根据钉钉官方给出的历次更新版说明&#xff0c;这个新的版本&#xf…...

Leetcode经典题13--接雨水

题目描述 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 输入输出示例 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1…...

yarn修改缓存位置

查看缓存位置 以下三个命令分别为&#xff1a;bin是yarn存储命令的二进制文件&#xff0c;global存储全局node_modules &#xff0c;cache存储用下下载缓存&#xff0c;查看本机目前的目录&#xff1a; 查看bin目录命令&#xff1a;yarn global bin 查看global目录命令&…...

OpenHarmony-3.HDF input子系统(5)

HDF input 子系统OpenHarmony-4.0-Release 1.Input 概述 输入设备是用户与计算机系统进行人机交互的主要装置之一&#xff0c;是用户与计算机或者其他设备通信的桥梁。常见的输入设备有键盘、鼠标、游戏杆、触摸屏等。本文档将介绍基于 HDF_Input 模型的触摸屏器件 IC 为 GT91…...

RabbitMQ 消息持久化/镜像队列/lazy对时延影响

测试背景&#xff1a; 不同条件下RabbitMQ不同队列类型的生产时延测试&#xff1a; 测试环境&#xff1a; 机型&#xff1a;rabbimtq.2u4g.cluster 背景流量&#xff1a;1000 TPS 测试条件&#xff1a; 消息大小 4k&#xff0c;消息条数为1000条&#xff0c;时延取值为平均…...

【深度学习】深刻理解Swin Transformer

Swin Transformer 是一种基于 Transformer 的视觉模型&#xff0c;由 Microsoft 研究团队提出&#xff0c;旨在解决传统 Transformer 模型在计算机视觉任务中的高计算复杂度问题。其全称是 Shifted Window Transformer&#xff0c;通过引入分层架构和滑动窗口机制&#xff0c;S…...

[2015~2024]SmartMediaKit音视频直播技术演进之路

技术背景 2015年&#xff0c;因应急指挥项目需求&#xff0c;我们实现了RTMP推送音视频采集推送&#xff08;采集摄像头和麦克风数据&#xff09;模块&#xff0c;在我们做好了RTMP推送模块后&#xff0c;苦于没有一个满足我们毫秒级延迟诉求的RTMP播放器&#xff0c;于是第一…...

redis 使用Lettuce 当redis挂掉重启之后 网络是怎么重新连接

Lettuce是一个高性能的Java Redis客户端&#xff0c;支持同步、异步和反应式编程模式 Lettuce的核心功能包括&#xff1a; ‌高性能‌&#xff1a;通过使用Netty作为底层网络通信框架&#xff0c;实现了非阻塞IO&#xff0c;提高了性能。‌丰富的API‌&#xff1a;提供了丰富…...

【IntelliJ IDEA 集成工具】TalkX - AI编程助手

前言 在数字化时代&#xff0c;技术的迅猛发展给软件开发者带来了更多的挑战和机遇。为了提高技术开发群体在繁多项目中的编码效率和质量&#xff0c;他们需要一个强大而专业的工具来辅助开发过程&#xff0c;而正是为了满足这一需求&#xff0c;TalkX 应运而生。 一、概述 1…...