Lua调用C#

 Lua没有办法直接访问C#,一定是先从C#调用Lua后

才把核心逻辑交给Lua来编辑

Lua使用C#类

Main.cs:

public class Main : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        LuaMgr.GetInstance().Init();
        LuaMgr.GetInstance().DoLuaFile("Main");
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

LuaCallCSharp.cs

public class Test
{
    public void Speak(string str)
    {
        Debug.Log("Test1" + str);
    }
}
namespace MrTang
{
    public class Test2
    {
        public void Speak(string str)
        {
            Debug.Log("Test2" + str);
        }
    }
}
public class LuaCallCSharp : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Main.lua:

print("主Lua启动")
--Unity中写lua执行
--xlua帮我们处理
--只要使执行lua脚本 都会自动进入重定向函数中找文件
--require("Test") 
require("Lesson1_CallClass")

Lesson1_CallClass.lua

print("*************Lua调用C#类相关知识点***************")

--lua中使用c#的类的固定套路
--CS.命名空间.类名
--Unity的类 比如GameObject Transform 都再UnityEngine命名空间下 —— CS.UnityEngine.类名
--例如 CS.UnityEngine.GameObject

--通过C#中的类 实例化一个对象 lua中没有new 所以我们直接类名括号就是实例化对象
--默认调用无参构造

local obj1 = CS.UnityEngine.GameObject()
local obj2 = CS.UnityEngine.GameObject("Test")

--为了方便使用和节省性能 定义全局变量存储 C#中的类
GameObject = CS.UnityEngine.GameObject
local obj3 = GameObject("Test2")

--类中的静态对象 可以直接使用.来调用
local obj4 = GameObject.Find("Test")

--得到对象中的成员变量 直接对象.即可
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.Test()
t:Speak("test说话")

local t2 = CS.MrTang.Test2()
t2:Speak("test2说话")

--继承了Mono的类 不能直接new
local obj5 = GameObject("加脚本测试")
--通过GameObject的AddComponent添加脚本
--xlua提供了一个重要方法 typeof 可以得到类的type
--xlua不支持 无参泛型函数 所以我们要用另一个重载
obj5:AddComponent(typeof(CS.LuaCallCSharp))

Lua使用C#枚举

print("*************Lua调用C#枚举相关知识点***************")


--枚举调用
--调用Unity中的枚举
--枚举的调用规则和类的调用规则是一样的
--CS.命名空间.枚举名.枚举成员

PrimitiveType = CS.UnityEngine.PrimitiveType
GameObject = CS.UnityEngine.GameObject
local obj = GameObject.CreatePrimitive(PrimitiveType.Cube)

--自定义枚举使用方法一样 只是要注意命名空间
E_MyEnum = CS.E_MyEnum
local c = E_MyEnum.Idle
print(c)
--枚举转换相关

--数值转枚举
local a = E_MyEnum.__CastFrom(1)
print(a)

--字符串转枚举
local b = E_MyEnum.__CastFrom("Atk")
print(b)

Lua使用C#数组、list和字典

print("*************Lua调用C#数组相关知识点***************")

local obj = CS.Lesson3()


--Lua使用C#相关知识

--长度 userdata数据类型
--C#怎么获取 lua就怎么获取 不能用lua中的#去获取长度
print(obj.array.Length)

--访问元素
print(obj.array[0])

--遍历 要注意 lua中索引从1开始
--但是 数组是C#那边的规则 所以还是得按C#的来
--注意最大值要-1
for i=0,obj.array.Length-1 do
	print(obj.array[i])
end

--在Lua中创建一个C#的数组 Lua中表示数组和List可以用表
--但是 我们要使用C#中的Array类中的静态方法即可(Lua中不能用new)
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 do
	print(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("10238910823")
print(list3[0])


print("*************Lua调用C#Dictionary相关知识点***************")
--使用和C#一致
obj.dic:Add	(1,"123")
print(obj.dic[1])
for k,v in pairs(obj.dic) do
	print(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) do
	print(k,v)
end
--在Lua中创建的字典 直接通过中括号得不到 结果是nil

print(dic2["123"])
print(dic2:TryGetValue("123"))
--如果要通过键获取值 要通过这个固定方法
print(dic2:get_Item("123"))
dic2:set_Item("123",nil)
print(dic2:get_Item("123"))

Lua使用C#拓展方法

public static class Tools
{
    public static void Move(this Lesson4 obj)
    {
        Debug.Log(obj.name + "移动");
    }
}
public class Lesson4
{
    public string name = "123123";
    public void Speak(string str)
    {
        Debug.Log("str");
    }
    public static void Eat()
    {
        Debug.Log("吃东西");
    }
}
print("*************Lua调用C#拓展方法相关知识点***************")

Lesson4 = CS.Lesson4

--使用静态方法
--CS.命名空间.类名.静态方法名
Lesson4.Eat()

--成员方法 实例化出来用
local obj = Lesson4()
--成员方法一定要用冒号
obj:Speak("string")

--使用拓展方法 和使用成员方法一致
--要调用 C#某个类中的拓展方法 一定要在拓展方法的静态类前加上LuaCallCSharp特性 并在Unity中生成Lua代码
obj:Move()

Lua使用C# ref和out函数

public class Lesson5
{
    public int RefFun(int a,ref int b,ref int c,int d)
    {
        b = a + d;
        c = a - d;
        return 100;
    }

    public int OutFun(int a, ref int b, ref int c, int d)
    {
        b = a;
        c= d;
        return 200;
    }
    public int RefOutFun(int a,out int b,ref int c)
    {
        b = a * 10;
        c = a * 20;
        return 300;
    }
}
print("*************Lua调用C#ref和out方法相关知识点***************")


Lesson5 = CS.Lesson5
local 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)

--out参数 会以多返回值的形式返回lua
--如果函数存在返回值那么第一个值就是改返回值
--之后的返回值就是out的结果 从左到右一一对应
--out参数 不需要传占位置的值
print("****************************")

local a,b,c = obj:OutFun(20,30)
print(a)
print(b)
print(c)

--综合使用时 综合上面的规则
--ref 需要站位 out不需要
--第一个是函数的返回值 之后从左到右依次对应ref或out
print("****************************")
local a,b,c = obj:RefOutFun(20,1)
print(a)
print(b)
print(c)

Lua使用C#重载函数

public class Lesson6
{
    public int Calc()
    {
        return 100;
    }
    public int Calc(int a,int b)
    {
        return a + b;
    }
    public int Calc(int a)
    {
        return a;
    }
    public float Calc(float a) 
    {
        return a;
    }
}
print("*************Lua调用C#重载函数相关知识点***************")

local obj = CS.Lesson6()
--虽然Lua自己不支持重载函数
--但是Lua支持调用C#中的重载函数
print(obj:Calc())
print(obj:Calc(1,3))

--Lua虽然支持调用C#重载函数
--但是因为Lua中的数值类型只有Number
--所以对C#中多精度重载函数支持不好 会分不清
--在使用时会出现意想不到的事
print(obj:Calc(10))
print(obj:Calc(10.3))--输出了0

--解决重载函数含糊问题
--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.9))

Lua使用C#委托和事件

public class Lesson7
{
    //声明委托和事件
    public UnityAction del;
    public event UnityAction eventAction;
    public void DoEvent()
    {
        if(eventAction != null)
            eventAction();
    }
    public void ClearEvent()
    {
        eventAction = null;
    }
}
print("*************Lua调用C#委托相关知识点***************")

local obj = CS.Lesson7()

--委托可以用来装函数
--使用C#中的委托 装lua中的函数
local fun  = function (  )
	print("Lua函数")
end
print("****************************")
--Lua中没有复合运算符 不能+=
--如果第一次往委托中加函数 因为是nil 不能直接+
--所以第一次要先赋值=
obj.del = fun
--obj.del = 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()
--清空所有的函数
obj.del = nil
--清空后要先赋值
obj.del = fun

obj.del()

print("*************Lua调用C#事件相关知识点***************")
local fun2 = function ()
	print("Action")
end
print("****************************")
--事件加减函数和委托非常不一样
--lua中使用C#事件 加函数
--有点类似于使用成员方法 冒号事件名("+",函数变量)
obj:eventAction("+",fun2)
--最好不要这么写
obj:eventAction("+",function ()
	print("Action")
end)

obj:DoEvent()
print("****************************")
obj:eventAction("-",fun2)
obj:DoEvent()
--清楚事件 不能直接设空
--obj.eventAction=nil会报错
obj:ClearEvent()
obj:DoEvent()

Lua使用C#二维数组

public class Lesson8
{
    public int[,] array = new int[2, 3] { { 1, 2, 3 }, { 4, 5, 6 } };
    
}
print("*************Lua调用C#二维数组相关知识点***************")

local obj = CS.Lesson8()

--获取长度
print("行:"..obj.array:GetLength(0))
print("列:"..obj.array:GetLength(1))

--获取元素
--不能通过[0,0]或[0][0]来访问元素 会报错
print(obj.array:GetValue(0,0))
print(obj.array:GetValue(1,0))

for i = 0,obj.array:GetLength(0)-1 do
	for j=0,obj.array:GetLength(1)-1 do
		print(obj.array:GetValue(i,j))
	end
end

Lua使用C#的null和nil比较

//为object 拓展一个方法
[LuaCallCSharp]
public static class Lesson9
{
    //拓展一个为Objcet判空的方法 主要给Lua用 lua没法用null和nil比较
    public static bool IsNull(this Object obj)
    {
        return obj == null;
    }
}
print("*************Lua调用C# nil和null比较相关知识点***************")

--往场景对象上添加一个脚本 如果不存在就加 存在就不加
GameObject = CS.UnityEngine.GameObject
Rigidbody = CS.UnityEngine.Rigidbody

local obj = GameObject("添加测试脚本")
--得到身上的刚体组件 如果没有就加 有就不加
local rig = obj:GetComponent(typeof(Rigidbody))
print(rig)
--判断空
--nil和null没法进行==比较(rig == nil)
--第一种方法:rig:Equals(nil) then
--[[if rig:Equals(nil) then
	print("123")
	rig = obj:AddComponent(typeof(Rigidbody))
end]]
--第二种
--[[if IsNull(rig) then
	print("123")
	rig = obj:AddComponent(typeof(Rigidbody))
end]]
--第三种 在C#中添加方法
if rig:IsNull() then
	print("123")
	rig = obj:AddComponent(typeof(Rigidbody))
end
print(rig)

Lua和系统类或委托相互使用

public static class Lesson10
{
    [CSharpCallLua]
    public static List<Type> csharpCallLuaList = new List<Type>()
    {
        //在这里面加上需要加上[CSharpCallLua]特性的type
        typeof(UnityAction<float>)
    };

    [LuaCallCSharp]
    public static List<Type> luaCallCSharpList = new List<Type>()
    {
        typeof(GameObject),
        typeof(Rigidbody)
    };
}
GameObject = CS.UnityEngine.GameObject
UI = CS.UnityEngine.UI

local slider = GameObject.Find("Slider")
print(slider)

local sliderScript = slider:GetComponent(typeof(UI.Slider))
print(sliderScript)
sliderScript.onValueChanged:AddListener(function (f)
	print(f)
end)

Lua使用C#协程

print("*************Lua调用C# 协程相关知识点***************")
--xlua提供的一个工具表
--一定是要通过require调用后才能用
util = require("xlua.util")
--C#中协程启动都是通过继承了Mono的类 通过里面的启动函数StartCoroutine



GameObject = CS.UnityEngine.GameObject
WaitForSeconds = CS.UnityEngine.WaitForSeconds
--在场景中新建一个空物体 挂一个脚本上去 脚本继承mono使用它来开启协程
local obj = GameObject("Coroutine")
local mono = obj:AddComponent(typeof(CS.LuaCallCSharp))
--希望用来被开启的协程函数
fun = function ()
	local a = 1
	while true do
		--Lua中不能直接使用C#中的yield return
		--就使用Lua中的协程返回
		coroutine.yield(WaitForSeconds(1))
		print(a)
		a = a + 1
		if a>5 then
			mono:StopCoroutine(b)
		end
	end
end
--我们不能直接将lua函数传入开启协程
--如果要把lua函数当做协程函数传入
--必须先调用xlua.util中的cs_generator(lua函数)
b = mono:StartCoroutine(util.cs_generator(fun))

Lua使用C#泛型函数

print("*************Lua调用C# 泛型函数相关知识点***************")

local obj = CS.Lesson12()
local child = CS.Lesson12.TestChild()
local father = CS.Lesson12.TestFather()

--支持有约束有参数的泛型函数
obj:TestFun1(child,father)
obj:TestFun1(father,child)

--lua中不支持没有约束的泛型函数
--obj:TestFun2(child)

--Lua中不支持有约束但是没有参数的泛型函数
--obj:TestFun3()


--Lua中不支持 非Class的约束
--obj:TestFun4(child)


--有一定使用限制
--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)
public class Lesson12
{
    public interface ITest
    {

    }
    public class TestFather
    {

    }

    public class TestChild:TestFather,ITest
    {

    }
    public void TestFun1<T>(T a, T b) where T : TestFather
    {
        Debug.Log("有参数 有约束的泛型方法");
    }
    public void TestFun2<T>(T a)
    {
        Debug.Log("有参数 没约束的泛型方法");
    }
    public void TestFun3<T>()where T : TestFather
    {
        Debug.Log("有约束 没参数的泛型函数");
    }
    public void TestFun4<T>(T a)where T : ITest
    {
        Debug.Log("有约束有参数 但是约束不是类");
    }
}

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值