Lua调用C#
lua不能直接访问C#,只能先从C#调用Lua脚本后再用Lua调用C#
lua调用C#类
-- Lua调用C#类知识点
print("***Lua调用C#类知识点")
-- CS.命名空间.类名
-- CS.UnityEngine.类名
-- 使用C#类实例化对象,默认调用的是无参构造
local obj1 = CS.UnityEngine.GameObject()
-- 为了方便使用和节约性能通过定义全局变量存储C#中的类
UE = CS.UnityEngine;
GameObject = UE.GameObject;
Debug = UE.Debug;
Vector3 = UE.Vector3;
local obj2 = GameObject("测试")
-- 类中的静态对象可以直接使用类.来调用
local obj3 = GameObject.Find("测试")
-- 对象的成员变量也是对象名.来调用
print(obj3.transform.position)
-- 成员方法要用:调用
obj3.transform:Translate(Vector3.forward)
--[[
public class TestLua
{
public void speak(string str)
{
Debug.Log("testlua");
Debug.Log(str);
}
}
namespace Test
{
public class TestLua2
{
public void speak(string str)
{
Debug.Log("testlua2");
Debug.Log(str);
}
}
}
]]
-- 自定义类没命名空间直接用 CS.类名 有命名空间就CS.命名空间.类名
local obj4 = CS.TestLua()
obj4:speak("omg")
local obj5 = CS.Test.TestLua2()
obj5:speak("omg")
-- 继承Mono的类不能直接new
local obj6 = GameObject("脚本测试") -- 实例化一个新的类
-- xlua提供的typeof()可以得到类的Type
-- xlua不支持无参泛型所以要用AddComponent的重载方法
obj6:AddComponent(typeof(CS.TestLuaMono)); -- 这里的TestLuaMono是一个继承了Mono的自定义类
lua调用C#枚举
-- 枚举调用规则和类调用一样 CS.命名空间.枚举名.枚举成员
PrimitiveType = UE.PrimitiveType
local obj = GameObject.CreatePrimitive(PrimitiveType.Cube)
obj.name = "枚举立方体"
-- 自定义枚举跟Unity自带枚举调用一样 CS[.命名空间].枚举名.枚举成员
-- 有命名空间就带命名空间没有就算
--[[
public enum TestEnum
{
S1,
S2
}
]]
-- 枚举转换
-- 数值转枚举
MyEnum = CS.TestEnum
local a = MyEnum.__CastFrom(1)
print(a) -- S2 1
-- 字符串转枚举
local b = MyEnum.__CastFrom("S1")
print(b) -- S1 0
lua调用C#List和Dictionary
print("***lua调用list和dictionary")
--[[
public class TestLuaListAndDic
{
public int[] i_arr = new int[5] { 1, 2, 3, 4, 5 };
public List<int> li_arr = new List<int>();
public Dictionary<string,int> dic_si = new Dictionary<string, int>();
public void Test1(int[] arr)
{
for (var i = 0; i < arr.Length; i++)
{
Debug.Log(arr[i]);
}
}
}
]]
local obj = CS.TestLuaListAndDic()
-- 数组长度
print(obj.i_arr.Length)
-- 数组元素
print(obj.i_arr[0])
-- 遍历 lua索引从1开始但c#是从0开始
-- 且lua这里相对于<=所以要用长度-1
for i = 0,obj.i_arr.Length-1 do
print(obj.i_arr[i])
end
-- 创建数组 要使用C#中Array类的静态方法CreateInstance
-- 第一个参数是C#中的数据类型 第二个参数是长度
Array = CS.System.Array
int = CS.System.Int32
obj:Test1(Array.CreateInstance(typeof(int),5))
-- lua 调用list相关方法
-- 成员方法调用用 :
-- 成员方法调用用 :
-- 成员方法调用用 :
obj.li_arr:Add(1)
obj.li_arr:Add(2)
obj.li_arr:Add(3)
obj.li_arr:Remove(2)
for i = 0, obj.li_arr.Count-1 do
print(obj.li_arr[i])
end
-- lua创建List对象
-- 这里相对于声明一个类CS.System.Collections.Generic.List(这里的是list里存什么类型)
List_String = CS.System.Collections.Generic.List(CS.System.String) -- 相对于List<String>
local l_s = List_String() -- 相对于 new List<String>
l_s:Add("aaa")
print(l_s[0])
-- lua 调用dictionary相关方法
-- 用法和C#一样
obj.dic_si:Add("qwq",7)
print(obj.dic_si["qwq"]) -- lua中创建的字典通过obj.dic_si["qwq"]得不到值,如果要通过键获取/设置值要用 对象名:get_Item([key]) 对象名:set_Item([k,v])
-- 遍历
for k,v in pairs(obj.dic_si) do
print(k,v)
end
-- 在lua创建一个字典对象
local Dic_S_V3 = CS.System.Collections.Generic.Dictionary(CS.System.String,Vector3) -- 相对于Dictionary<String,Vector3>
local dic1 = Dic_S_V3()
dic1:Add("vf",Vector3.forward);
-- lua中创建的字典通过obj.dic_si["qwq"]得不到值,如果要通过键获取/设置值要用 对象名:get_Item([key]) 对象名:set_Item([k,v])
print(dic1['vf'])
lua调用C# 拓展方法
print("***lua调用C#中拓展方法")
--[[
public static class TestLuaFuncExtendTools
{
public static void move(this TestLuaFuncExtend obj)
{
Debug.Log("move");
}
}
public class TestLuaFuncExtend
{
public string name = "test";
public void speak(string str)
{
Debug.Log(str);
}
public static void eat()
{
Debug.Log("eat");
}
}
]]
TLFE = CS.TestLuaFuncExtend;
TLFE.eat()
local obj1 = TLFE()
print(obj1.name)
-- 成员方法
obj1:speak()
-- 拓展方法
-- 且需要在拓展类前面加上[LuaCallCSharp] 然后用xLua生成代码
-- 建议lua中用使用的类都加上该特性,可以提升性能
obj1:move() -- 使用拓展方法和使用成员方法一样使用:
lua调用C# ref和out方法
print("***lua调用C#中ref和out方法")
--[[
public class TestLuaRefOrOutFunc
{
public int refFun(ref int a,int b)
{
a += b;
return a+b;
}
public int outFun(out int a,int b)
{
a = 1;
a += b;
return a+b;
}
public int allFun(ref int a, out int b)
{
b = a;
a += b;
return a+b;
}
}
]]
TC1 = CS.TestLuaRefOrOutFunc
local obj1 = TC1()
-- ref参数会以多返回值的形式返回得lua
local ab,a = obj1:refFun(10,5); -- 如果函数存在返回值,第一个值就是函数返回值,后续就算ref的结果从左到右一一对应且ref要一个默认值
print(ab)
print(a)
-- out同理ref
ab,a = obj1:outFun(5); -- out可以不用传一个默认值占位
print(ab)
print(a)
ab,a = obj1:allFun(5); -- out可以不用传一个默认值占位
print(ab)
print(a)
lua调用C# 重载函数
print("***lua调用C#中重载函数")
--[[
public class TestLuaFuncRw
{
public void func1()
{
Debug.Log("hello world");
}
public void func1(string str)
{
Debug.Log("str");
}
public void func1(int a, int b)
{
Debug.Log(a+b);
}
}
]]
TC2 = CS.TestLuaFuncRw
local obj1 = TC2()
-- lua调用C#重载函数直接调用就行了
-- 但因为lua数值类型只有number对C#中多精度的重载函数支持不好,使用时会出现预料之外的结果
obj1:func1()
obj1:func1("qwq")
obj1:func1(3,4)
-- 解决重载函数合糊的问题
-- xlua提供了解决方案 反射机制
-- 这种方法只做了解 尽量别用
-- Type是反射的关键类
-- 得到函数相关信息
local m1 = typeof(CS.TestLuaFuncRw):GetMethod("func1",{typeof(CS.System.Int32),typeof(CS.System.Int32)})
-- typeof(类名):GetMethod(重载方法名,{typeof(参数1类型),typeof(参数2类型),..})
-- 通过xlua提供的方法转成lua函数来使用
local f1 = xlua.tofunction(m1)
f1(obj1,8,8) -- 这里的第一个参数是调用者也就是实例对象
-- 如果是静态方法就第一个参数就不用传实例对象
lua调用C# 委托和事件
print("***lua调用C#中委托和实践")
--[[
public class TestLuaAction
{
public UnityAction Action;
public event UnityAction eventAction;
public void doEvent()
{
if(eventAction != null) eventAction.Invoke();
}
}
]]
TC3 = CS.TestLuaAction
local obj1 = TC3()
-- lua中第一次往委托中加函数
-- 需要先进行赋值然后才能继续加函数
obj1.Action = function ()
print("helloworld")
end
-- 不建议这样写建议声明一个变量接收函数这样方便移除
obj1.Action = obj1.Action + function ()
print("helloworld2")
end
-- 建议这样写
local fun1 = function ()
print("helloworld3")
end
obj1.Action = obj1.Action + fun1
obj1.Action();
obj1.Action = obj1.Action - fun1
obj1.Action()
-- 清空委托中所有存储的函数
obj1.Action = nil
-- 清空就得重新赋值一边才能再加
-- 事件的写法和委托不一样
obj1:eventAction("+",fun1);
obj1:eventAction("+",fun1);
obj1:eventAction("-",fun1);
obj1:doEvent()
-- 事件不能直接赋nil清空
-- 在C#类声明一个成员方法在c#里面将事件变量赋null
-- 然后在lua里调用
lua使用C# 二维数组
print("***lua调用C#中二维数组")
--[[
public class TestLuaArray
{
public int[,] arrs = new int[,]{{1,2,3},{1,2,3}};
}
]]
TC4 = CS.TestLuaArray
local obj2 = TC4()
-- 获取长度
print(obj2.arrs:GetLength(0)) -- 行长度
print(obj2.arrs:GetLength(1)) -- 列长度
-- print(obj2.arrs.Length)
-- 获取元素
print(obj2.arrs:GetValue(0,0)) -- 用数组自带的成员方法参数1行索引,参数2列索引
-- 遍历
for i = 0,obj2.arrs:GetLength(0) - 1 do
for j = 0,obj2.arrs:GetLength(1) - 1 do
print(obj2.arrs:GetValue(i,j))
end
end
lua使用C# 的null和nil比较
-- 判空 nil和null没法进行==比较
-- 要用对象名:Equals(nil)进行比较
-- 但如果对象本身就是null 则会报错
function isNull(obj)
if obj == nil or obj:Equals(nil)
return true
return false
end
给C# 的系统类添加特性
public static class ClassName{
[CSharpCallLua]
// 会给这个列表内的所有类型加上特性
public static List<Type> list = new List<Type>(){
typeof(UnityAction<float>) // 要加特性的系统类
}
[LiaCallCSharp]
// 会给这个列表内的所有类型加上特性
public static List<Type> list2 = new List<Type>(){
typeof(UnityAction<float>) // 要加特性的系统类
}
}
一定要在静态类中,改变后要重新生成代码
lua使用C# 中的协程
print("***lua调用C#协程")
-- 在场景中新建一个空物体
local obj = GameObject("协程")
-- 给创建的空物体添加一个继承Mono的脚本
local mono = obj:AddComponent(typeof(CS.TestLuaMono));
-- 利用这个脚本开启协程
-- 协程函数
fun = function ()
local a= 1
while a do
a = a+1
-- 不能使用yield return
-- 使用lua中的协程返回
print(a)
if(a>10) then
mono:StopCoroutine(c1); -- 停止和c#中一样
end
coroutine.yield(WaitForSeconds(1))
end
end
-- 不能直接将lua函数传入协程开启
-- 得先调用xlua.util的cs_generator()方法
util = require("xlua.util")
c1 = mono:StartCoroutine(util.cs_generator(fun))
lua 使用C# 中的泛型函数
print("***lua调用泛型函数")
--[[
public class TestLuaTFunc
{
public void fun1<T>(T a, T b)
{
Debug.Log(a);
}
}
]]
local obj = CS.TestLuaTFunc();
-- 不支持 obj:fun1(1,2)
-- 支持有约束有参数的泛型函数
-- 不支持·没有约束的泛型函数
-- 不支持·有约束·没参数的泛型函数
-- 不支持·非class的约束
-- 让不能用的泛型函数能用的流程
-- 有限制只有Mono打包支持,il2cpp打包,如果泛型参数是引用类型才可以使用
-- 获取通用函数
local ge_fun1 = xlua.get_generic_method(CS.TestLuaTFunc,"fun1") -- 参数1:类名,参数2:函数名字符串
-- 指定泛型类型
local fun1_int = ge_fun1(CS.System.Int32)
-- 调用
fun1_int(obj,1,2) -- 非静态函数第一个参数要传调用对象