|
启动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)endclassObj:Method6(myDelegate)--接收C#多返回数值--C#函数的返回值(如果有的话)算一个返回值,out算一个返回值,-- ref算一个返回值,然后从左往右对应lua的多返回值。local num1=10local num2=20local res1,res2,res3=classObj:Method7(num1,num2)--res1是返回值,res2和res3按参数顺序对应有out或者ref的参数print("res1="..res1) --输出结果: 110print("res2="..res2) --输出结果: 3000print("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=newList<Type>(){typeof(GameObject),typeof(Dictionary<string,int>),};然后把以上代码放入一个静态类中即可。三: 实际开发过程中,lua 调用C# 用的比较多。xlua 的优点体现的没有必要每次改的时候,都要生成代码。主要原理是依赖于编译器环境下,利用反射来动态生成代码接口。四: 在标有“[XLua.LuaCallCSharp]”的C#类中,添加新的方法后,如果是生成了代码类,则必须重新生成或者删除,否则Xlua 用以前生成的,进行注册查询,会出现lua 异常:“试图访问一个nil 的方法” |
|