启动Lua脚本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
//本脚本启动Lua文件
public class LuaCallCsharpBase : MonoBehaviour {
LuaEnv env = null;
private void Start()
{
env = new LuaEnv();
env.DoString("require 'LuaCallCSharp'"); //LuaCallCSharp.lua.txt
}
private void OnDestroy()
{
env.Dispose();
}
}
LuaCallCSharp.lua.txt
print("测试lua文件是否正确加载")
--[[ 一: 学习 lua 调用 Unity 系统 API ]]--
-- 所有C#相关的都放到CS下,包括构造函数,静态成员属性、方法。
--1: lua 中实例化一个 Unity 的对象
local newGo=CS.UnityEngine.GameObject()
newGo.name="New GameObject"
--2: 查找游戏物体
-- 学习lua 访问Unity API 中静态属性与方法
local TxtGo=CS.UnityEngine.GameObject.Find("Txt_Logo");
TxtGo.name="Modify Name"
--3: 得到游戏对象上的组件,学习使用冒号与句号(":",“.”)
local txtLogo=TxtGo:GetComponent("UnityEngine.UI.Text")
txtLogo.text="公告系统"
--[[ 二: 学习 lua 调用自定义C#脚本 ]]--
--lua中使用冒号,表示成员方法的调用。它自动完成把当前对象作为一个参数,传入方法。
--lua中使用点,则表示静态属性与方法调用。它需要手工往方法中传递当前对象
--类
--如果有命名空间CS后面要加命名空间,比如CS.XluaPro.IsInvokedClass(XluaPro为命名空间)
local IsInvoked=CS.IsInvokedClass
--实例化
local classObj=IsInvoked() --自动调用父类与子类的构造函数
--调用普通方法
classObj:Mehtod1() --ok
--classObj.Mehtod1() --语法报错!
classObj.Mehtod1(classObj) --语法OK
--调用父类的字段与方法
classObj:ShowFatherInfo(); --调用父类的方法
print(classObj.FatherClassName) --调用父类的公共字段
print(classObj.ChildClassName) --调用子类的公共字段
--测试调用C#方法重载
--有限重载,无法区分浮点和整型,精度,调用的C#函数是代码中排前面的那个
classObj:Method2(10,20)
classObj:Method2("abc","def")
--测试C#中带有params 关键字的方法
local intResult=classObj:Method3(20,70,"Hello ","World","EveryOne")
print("调用parmas关键字的方法,返回数值= "..intResult)
--测试lua调用C#中带有结构体参数的方法
--lua 使用一个表,来映射C#的结构体。
--定义一个表
myStructTable={x="C#语言",y="lua语言"}
classObj:Method4(myStructTable)
--测试lua调用C#中带有接口参数的方法
--lua 使用一个表,来映射C#的接口。
--Unity里面要生成代码
--定义一个表
myInterfaceTable=
{
x=1000,
y=300,
Speak=function()
print("lua中 Speak 方法被调用!")
end
}
classObj:Method5(myInterfaceTable)
--定义lua调用C#中带有委托参数的方法
--Unity里面要生成代码
--定义函数
myDelegate=function(num)
print("lua 中对应委托方法。参数num="..num)
end
classObj:Method6(myDelegate)
--接收C#多返回数值
--C#函数的返回值(如果有的话)算一个返回值,out算一个返回值,
-- ref算一个返回值,然后从左往右对应lua的多返回值。
local num1=10
local num2=20
local res1,res2,res3=classObj:Method7(num1,num2)
--res1是返回值,res2和res3按参数顺序对应有out或者ref的参数
print("res1="..res1) --输出结果: 110
print("res2="..res2) --输出结果: 3000
print("res3="..res3) --输出结果: 999
--lua中可以直接调用具有泛型为参数的方法
myTable8={"lua语言","C#语言","C++语言"}
classObj:Method8(myTable8);
--通过另外定义一个方法(Method_InvokeGenger)来调用泛型方法
--让C#方法运行起来。
classObj:Method_InvokeGenger()
--lua中直接调用C#中定义的泛型方法 (错误)
--local maxNum=CS.XluaPro.MyGengerric:GetMax<int>(20,30) --报语法错误
--print("maxNum="..maxNum)
--lua调用C#中一个测试方法
--c#定义一个方法,在方法内通过c#的扩展方法来调用泛型方法,
classObj:Test8_InvokeExtensionMethod();
--演示: 在lua中通过调用"扩展方法",来间接完成对C#“泛型方法”功能的实现。
-- 可以重载多个扩展方法来应用不同类型
--c#带有泛型方法的类和扩展类都要加上 [XLua.LuaCallCSharp]
--然后 重新生成代码
--MyGengerric 注意后面要加括号
--CS.XluaPro.MyGengerric():ExtGetMax(888,66) XluaPro是自定义的命名空间
local maxNum=CS.MyGengerric():ExtGetMax(888,66)
print("[在lua中扩展方法调用] maxNum="..maxNum)
Lua要调用c#的内容
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//定义结构体(建议结构体成员为小写)
public struct MyStruct
{
public string x;
public string y;
}
//定义接口
//有标记的基本上都要生成代码,搭建c#和Lua沟通的桥梁
[XLua.CSharpCallLua]
public interface MyInterface
{
int x { get; set; }
int y { get; set; }
void Speak();
}
//定义委托
[XLua.CSharpCallLua]
public delegate void MyDelegate(int num);
public class IsInvokedClass : IsInvoked_FatherClass
{
public string ChildClassName = "子类字段";
public IsInvokedClass()
{
Debug.Log("IsInvokedClass 子类构造函数");
}
public void Mehtod1()
{
Debug.Log("IsInvokedClass.cs/Mehtod1 方法");
}
/* 定义方法重载 */
public void Method2(int num1, int num2)
{
Debug.Log(GetType() + "/Method2()/ 重载方法/int浮点型/num1=" + num1 + " num2=" + num2);
}
public void Method2(float num1, float num2)
{
Debug.Log(GetType() + "/Method2()/ 重载方法/float浮点型/num1=" + num1 + " num2=" + num2);
}
public void Method2(string str1, string str2)
{
Debug.Log(GetType() + "/Method2()/ 重载方法/字符串类型/str1=" + str1 + " str2=" + str2);
}
//定义带有返回数值,有参数的方法,且有params 关键字
public int Method3(int num1, int num2, params string[] strArray)
{
Debug.Log(GetType() + "/Method3()/ 带有params关键字的方法/");
foreach (string item in strArray)
{
Debug.Log("输入的字符串内容:" + item);
}
return num1 + num2;
}
//带有结构体参数的方法
public void Method4(MyStruct p)
{
Debug.Log("测试lua调用结构体方法");
Debug.Log("p.x=" + p.x);
Debug.Log("p.y=" + p.y);
}
//方法具有接口为参数的
public void Method5(MyInterface p)
{
Debug.Log("测试lua调用具有接口为参数的方法");
Debug.Log("p.x=" + p.x);
Debug.Log("p.y=" + p.y);
p.Speak();
}
//方法具有委托为参数
public void Method6(MyDelegate p)
{
Debug.Log(GetType() + "/Method6()/委托参数:");
//调用
p.Invoke(88);
}
//定义一个具有多返回数值的方法
public int Method7(int num1, out int num2, ref int num3)
{
Debug.Log(GetType() + "/Method7()/测试lua接收C#的多返回数值");
num2 = 3000;
num3 = 999;
return num1 + 100;
}
//定义一个具有泛型方法为参数的。
public void Method8(List<string> strArray)
{
Debug.Log(GetType() + "/Method8()/这是一个具有泛型方法为参数的方法");
foreach (string item in strArray)
{
Debug.Log("泛型集合中的内容=" + item);
}
}
//C#方法中,调用我们自定义的泛型方法
public void Method_InvokeGenger()
{
int maxNum = 0;
int num1 = 100;
int num2 = 200;
MyGengerric obj = new MyGengerric();
maxNum = obj.GetMax<int>(num1, num2);
Debug.Log("C#中比较两个数字大小: "+maxNum);
//测试字符串的比较
//字符串的比较是比较第一个字符
// string maxStr = string.Empty;
// string str1 = "xd";
// string str2 = "kb";
// MyGengerric obj = new MyGengerric();
// maxStr = obj.GetMax<string>(str1, str2);
// Debug.Log("C#中比较两个字符串大小: " + maxStr);
}
//在C#中学习调用C#的扩展方法
public void Test8_InvokeExtensionMethod()
{
int maxNum = 0;
int num1 = 800;
int num2 = 200;
MyGengerric obj = new MyGengerric();
//通过扩展方法来调用泛型方法
maxNum = obj.ExtGetMax(num1, num2);
Debug.Log("[应用扩展方法] C#中得到最大数值=" + maxNum);
}
}
泛型方法的定义
/***
* 自定义泛型类
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
[XLua.LuaCallCSharp]
public class MyGengerric
{
public T GetMax<T>(T num1, T num2) where T : IComparable
{
if (num1.CompareTo(num2)<0)
{
return num2;
}
else {
return num1;
}
}
}
拓展MyGengerric的方法
/***
*
* 本类是一个“扩展方法”。
*
* 本类的功能是扩展原有“MyGengerric”类的功能。
*
* Description:
* 注意:
* 扩展方法有两大注意事项:
* A: 扩展方法类,必须是静态类。
* B: 定义的扩展方法的参数,第一个参数必须是this ,然后跟需要扩展的类名称全称。
*
*
*/
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[XLua.LuaCallCSharp]
public static class Extension_MyGengerric
{
/// <summary>
/// 定义扩展方法,对类MyGengerric扩展一个方法
/// </summary>
/// <param name="gen"></param>
/// <param name="num1"></param>
/// <param name="num2"></param>
/// <returns></returns>
public static int ExtGetMax(this MyGengerric gen, int num1, int num2)
{
if (num1<num2)
{
return num2;
}
else {
return num1;
}
}
}
Lua对其他的调用
1 枚举类型的调用
枚举值就像枚举类型下的静态属性一样。
testobj:EnumTestFunc(CS.Tutorial.TestEnum.E1)
上面的EnumTestFunc函数参数是Tutorial.TestEnum类型的
2 lua中可以使用“+/-”操作符,来增加与减少一个委托的调用。
delegate 属性可以用一个luaFunction 来赋值。
c#代码里, testobj里头有个事件定义是这样:public event Action TestEvent;
在Lua内
增加事件回调
testobj:TestEvent('+', lua_event_callback)
移除事件回调
testobj:TestEvent('-', lua_event_callback)
--------
event使用
Eg:
public event Action TestEvent;
增加事件回调:
testObj: TestEvent('+',lua_event_callback)
移除事件回调:
testObj: TestEvent('-',lua_event_callback)
Lua调用C#经验总结
一: lua 调用C#,需要在Xlua中生成“适配代码”,则在这个类打入一个
[luaCallCSharp] 的标签
二: 如果lua调用C#的系统API ,则无法拿到源代码,无法打入标签。则在配置文件(ExampleGenConfig.cs)
使用“静态列表”方式解决。
Eg:
public static List<Type> mymodule_LuaCallCS_List=new
List<Type>()
{
typeof(GameObject),
typeof(Dictionary<string,int>),
};
然后把以上代码放入一个静态类中即可。
三: 实际开发过程中,lua 调用C# 用的比较多。
xlua 的优点体现的没有必要每次改的时候,都要生成代码。主要原理是
依赖于编译器环境下,利用反射来动态生成代码接口。
四: 在标有“[XLua.LuaCallCSharp]”的C#类中,添加新的方法后,如
果是生成了代码类,则必须重新生成或者删除,否则Xlua 用以前生成的,
进行注册查询,会出现lua 异常:“试图访问一个nil 的方法”