找回密码
 立即注册
查看: 477|回复: 0

Tolua使用笔记六:在lua中操作C#的委托事件与在lua中对Unity的GameObject的操作

[复制链接]
发表于 2021-10-24 07:51 | 显示全部楼层 |阅读模式
原文地址:http://blog.csdn.net/qq_30168505/article/details/70555511

案例十一:
该案例主要讲解的是再Unity中对于C#中的委托的一些操作的方法
相比之前的一些例子,如果细心完整的看下来,会发现较开始的例子,这个例子算是比较复杂的了

核心代码就不贴了,太长了,如果没有经验,直接看这个例子,可能你已经晕在这里了,现在我就开始为大家细细的解析这样一篇代码
先从类TestEventListener开始说起,这是一个例子作者自己封装的一个类,里面包含了2种类型的委托和一些委托事件的变量和一些基础的方法
  1. public class TestEventListener : MonoBehaviour
  2. {
  3.     public delegate void VoidDelegate(GameObject go);
  4.     public delegate void OnClick(GameObject go);   
  5.     public OnClick onClick = delegate { };
  6.     public event OnClick onClickEvent = delegate { };   
  7.     public void SetOnFinished(OnClick click)
  8.     {
  9.         Debugger.Log("SetOnFinished OnClick");
  10.     }
  11.     public void SetOnFinished(VoidDelegate click)
  12.     {
  13.         Debugger.Log("SetOnFinished VoidDelegate");
  14.     }
  15.     [NoToLuaAttribute]
  16.     public void OnClickEvent(GameObject go)
  17.     {
  18.         onClickEvent(go);
  19.     }
  20. }
复制代码
这里大家先留下一个概念,后面会用到这个类,然后大家回到脚本TestDelegate这边来,这便是这个例子的入口类  按照惯例,作者一如既往的在Awake里面就几乎做完了所有的基本加载操作,我们都的时候也都是从这里开始:
  1.     void Awake()
  2.     {               
  3.         state = new LuaState();
  4.         state.Start();
  5.         LuaBinder.Bind(state);   //加载基本的Warp文件
  6.         Bind(state);
  7.         state.LogGC = true;
  8.         state.DoString(script);
  9.         GameObject go = new GameObject("TestGo");
  10.         listener = (TestEventListener)go.AddComponent(typeof(TestEventListener));
  11.         SetClick1 = state.GetFunction("SetClick1");
  12.         AddClick1 = state.GetFunction("AddClick1");
  13.         AddClick2 = state.GetFunction("AddClick2");
  14.         RemoveClick1 = state.GetFunction("RemoveClick1");
  15.         RemoveClick2 = state.GetFunction("RemoveClick2");
  16.         TestOverride = state.GetFunction("TestOverride");
  17.         AddEvent = state.GetFunction("AddEvent");
  18.         RemoveEvent = state.GetFunction("RemoveEvent");        
  19.     }
复制代码
首先自然是创建lua虚拟机,然后调用state.Start() 为虚拟机加载一些标准库。  然后则是使用LuaBinder.Bind(LuaState  state) 为该虚拟机中加载一些基本的class类型,就是之前在CustomSetting中添加并Warp的类型
之后的Bind()函数则是为lua虚拟机加载一些该例子特有的类型,平时我们完全可以不通过该方法添加,直接在CustomSetting中添加即可。
然后就是编译读取下面的lua脚本
  1.             function DoClick1(go)               
  2.                 print('click1 gameObject is '..go.name)                    
  3.             end
  4.             function DoClick2(go)               
  5.                 print('click2 gameObject is '..go.name)                              
  6.             end                       
  7.             function AddClick1(listener)       --添加点击事件DoClick1
  8.                 if listener.onClick then
  9.                     listener.onClick = listener.onClick + DoClick1                                                   
  10.                 else
  11.                     listener.onClick = DoClick1   
  12.                 end               
  13.             end
  14.             function AddClick2(listener)       --添加点击事件DoClick2
  15.                 if listener.onClick then
  16.                     listener.onClick = listener.onClick + DoClick2                     
  17.                 else
  18.                     listener.onClick = DoClick2
  19.                 end               
  20.             end
  21.             function SetClick1(listener)       --设置点击事件
  22.                 if listener.onClick then
  23.                     listener.onClick:Destroy()
  24.                 end
  25.                 listener.onClick = DoClick1         
  26.             end
  27.             function RemoveClick1(listener)    --移除点击事件DoClick1
  28.                 if listener.onClick then
  29.                     listener.onClick = listener.onClick - DoClick1      
  30.                 else
  31.                     print('empty delegate')
  32.                 end
  33.             end
  34.             function RemoveClick2(listener)    --移除点击事件DoClick2
  35.                 if listener.onClick then
  36.                     listener.onClick = listener.onClick - DoClick2   
  37.                 else
  38.                     print('empty delegate')                                
  39.                 end
  40.             end
  41.             --测试重载问题
  42.             function TestOverride(listener)
  43.                 listener:SetOnFinished(TestEventListener.OnClick(DoClick1))
  44.                 listener:SetOnFinished(TestEventListener.VoidDelegate(DoClick2))
  45.             end
  46.             function TestEvent()     --测试事件
  47.                 print('this is a event')
  48.             end
  49.             function AddEvent(listener)    --添加事件
  50.                 listener.onClickEvent = listener.onClickEvent + TestEvent
  51.             end
  52.             function RemoveEvent(listener)   --移除事件
  53.                 listener.onClickEvent = listener.onClickEvent - TestEvent
  54.             end
复制代码
然后创建了一个游戏物体,并为其绑定了一个最开始说到的那个TestEventListener组件;  在之后就是用Tolua#提供的luaFunction将之前读取脚本中的lua方法取出。。。。方法的含义我已经在旁边给出了注释
接下来就看看OnGUI中的代码,看看这里是如何调用这些方法的
  1. //UI面板绘制方法
  2.     void OnGUI()
  3.     {
  4.         if (GUI.Button(new Rect(10, 10, 120, 40), " = OnClick1"))
  5.         {
  6.             CallLuaFunction(SetClick1);
  7.         }
  8.         else if (GUI.Button(new Rect(10, 60, 120, 40), " + Click1"))
  9.         {
  10.             CallLuaFunction(AddClick1);
  11.         }
  12.         else if (GUI.Button(new Rect(10, 110, 120, 40), " + Click2"))
  13.         {
  14.             CallLuaFunction(AddClick2);
  15.         }
  16.         else if (GUI.Button(new Rect(10, 160, 120, 40), " - Click1"))
  17.         {
  18.             CallLuaFunction(RemoveClick1);
  19.         }
  20.         else if (GUI.Button(new Rect(10, 210, 120, 40), " - Click2"))
  21.         {
  22.             CallLuaFunction(RemoveClick2);
  23.         }
  24.         else if (GUI.Button(new Rect(10, 260, 120, 40), "+ Click1 in C#"))
  25.         {
  26.             LuaFunction func = state.GetFunction("DoClick1");
  27.             TestEventListener.OnClick onClick = (TestEventListener.OnClick)DelegateFactory.CreateDelegate(typeof(TestEventListener.OnClick), func);
  28.             listener.onClick += onClick;
  29.         }        
  30.         else if (GUI.Button(new Rect(10, 310, 120, 40), " - Click1 in C#"))
  31.         {
  32.             LuaFunction func = state.GetFunction("DoClick1");
  33.             listener.onClick = (TestEventListener.OnClick)DelegateFactory.RemoveDelegate(listener.onClick, func);
  34.             func.Dispose();
  35.             func = null;
  36.         }
  37.         else if (GUI.Button(new Rect(10, 360, 120, 40), "OnClick"))
  38.         {
  39.             if (listener.onClick != null)
  40.             {
  41.                 listener.onClick(gameObject);
  42.             }
  43.             else
  44.             {
  45.                 Debug.Log("empty delegate!!");
  46.             }
  47.         }
  48.         else if (GUI.Button(new Rect(10, 410, 120, 40), "Override"))
  49.         {
  50.             CallLuaFunction(TestOverride);
  51.         }
  52.         else if (GUI.Button(new Rect(10, 460, 120, 40), "Force GC"))
  53.         {
  54.             //自动gc log: collect lua reference name , id xxx in thread
  55.             state.LuaGC(LuaGCOptions.LUA_GCCOLLECT, 0);
  56.             GC.Collect();
  57.         }
  58.         else if (GUI.Button(new Rect(10, 510, 120, 40), "event +"))
  59.         {
  60.             CallLuaFunction(AddEvent);
  61.         }
  62.         else if (GUI.Button(new Rect(10, 560, 120, 40), "event -"))
  63.         {
  64.             CallLuaFunction(RemoveEvent);
  65.         }
  66.         else if (GUI.Button(new Rect(10, 610, 120, 40), "event call"))
  67.         {
  68.             listener.OnClickEvent(gameObject);
  69.         }
  70.     }
复制代码
这里涉及到该例子中的一个方法CallLuaFunction()  
  1. void CallLuaFunction(LuaFunction func)
  2.     {        
  3.         func.BeginPCall();
  4.         func.Push(listener);
  5.         func.PCall();
  6.         func.EndPCall();               
  7.     }
复制代码
其实就是对luaFunction的调用的一种封装,使得其默认总是以之前的那个TestEventListener组件为参数来调用LuaFunction  ·有了这些之后,我们就可以来很轻松的这些按钮的作用了!!!
首先是按钮” = OnClick1” ,该放啊对应的代码其实就是直接以TestEventListener组件为参数来调用lua的方法 SetClick1(listener)
该lua方法的代码如下:
  1.             function SetClick1(listener)       --设置点击事件
  2.                 if listener.onClick then
  3.                     listener.onClick:Destroy()
  4.                 end
  5.                 listener.onClick = DoClick1         
  6.             end
复制代码
1:在这段代码中我们可以看到 C#中的委托可以直接使用 if 语句判空 ,并且可以使用Delegate:Destory()来销毁该委托  2:对于C#中的委托的赋值可以直接使用 lua中的方法以赋值运算符赋值 例如 : listener.onClick = DoClick1

然后是按钮 ” + Click1” 和 按钮 ” + Click2 ” 这里讲解了如何为委托绑定额外的方法,相当于C#中的对于委托的+=操作
该部分lua方法的代码如下:
  1.            function AddClick1(listener)       --添加点击事件DoClick1
  2.                 if listener.onClick then
  3.                     listener.onClick = listener.onClick + DoClick1                                                   
  4.                 else
  5.                     listener.onClick = DoClick1   
  6.                 end               
  7.             end
  8.             function AddClick2(listener)       --添加点击事件DoClick2
  9.                 if listener.onClick then
  10.                     listener.onClick = listener.onClick + DoClick2                     
  11.                 else
  12.                     listener.onClick = DoClick2
  13.                 end               
  14.             end
复制代码
由于lua中不支持+=运算符,所以,在这里采用了后面的写法替代: Delegate = Delegate + 方法
相对应的有绑定也自然有取消绑定功能,体现该功能的按钮是分别是 ” - Click1” 和 ” - Click2 ” ,
lua代码如下:
  1.             function RemoveClick1(listener)    --移除点击事件DoClick1
  2.                 if listener.onClick then
  3.                     listener.onClick = listener.onClick - DoClick1      
  4.                 else
  5.                     print('empty delegate')
  6.                 end
  7.             end
  8.             function RemoveClick2(listener)    --移除点击事件DoClick2
  9.                 if listener.onClick then
  10.                     listener.onClick = listener.onClick - DoClick2   
  11.                 else
  12.                     print('empty delegate')                                
  13.                 end
  14.             end
复制代码
同样的,lua之中也不支持-=运算符,所以使用这样的写法 : Delegate = Delegate - 方法按钮”OnClick” 就不用看了哈 ,就是最基本的C#的委托调用
然后是 按钮 “Override” ,该按钮主要是为了向大家证实在lua中重载函数的正常使用
Tolua#是完全兼容重载函数的,同时还向大家展示了在lua中创建委托的写法
直接 委托类型(参数列表) 即可在lua中创建一个新的委托变量~~~,是不是很方便
对应的代码如下:
  1. function TestOverride(listener)
  2.                 listener:SetOnFinished(TestEventListener.OnClick(DoClick1))
  3.                 listener:SetOnFinished(TestEventListener.VoidDelegate(DoClick2))
  4.             end
复制代码
剩下的按钮 ” + Click in C# ” 和 ” - Click in C#” 则是展示了如何在C#中删除绑定的lua方法
  1.         if (GUI.Button(new Rect(10, 260, 120, 40), "+ Click1 in C#"))
  2.         {
  3.             LuaFunction func = state.GetFunction("DoClick1");
  4.             TestEventListener.OnClick onClick = (TestEventListener.OnClick)DelegateFactory.CreateDelegate(typeof(TestEventListener.OnClick), func);
  5.             listener.onClick += onClick;
  6.         }        
  7.         else if (GUI.Button(new Rect(10, 310, 120, 40), " - Click1 in C#"))
  8.         {
  9.             LuaFunction func = state.GetFunction("DoClick1");
  10.             listener.onClick = (TestEventListener.OnClick)DelegateFactory.RemoveDelegate(listener.onClick, func);
  11.             func.Dispose();
  12.             func = null;
  13.         }
复制代码
其实就是将lua方法取出到C#中,然后转成LuaFunction ,然后直接使用
  1. DelegateFactory.CreateDelegate 和 DelegateFactory.RemoveDelegate
复制代码
进行添加和删除,顺便友情提示,LuaFunction使用法之后要记得手动释放哟,否则会有GC  最后是对于在lua中操作C#的事件,其操作手法和委托极其相似,大家其实看一看就可以学会了,,基本上就是这些了
最后这个例子中需要用到的委托类型也都是要单独导出Warp的,操作手法其实就是将需要的委托类型添加到CustomSetting.cscustomDelegateList
样例写法如下:
  1.     public static DelegateType[] customDelegateList =
  2.     {        
  3.         _DT(typeof(Action)),
  4.         //_DT(typeof(Action)).SetAbrName("ActionGo"),
  5.         _DT(typeof(UnityEngine.Events.UnityAction)),      
  6.         _DT(typeof(TestEventListener.OnClick)),
  7.         _DT(typeof(TestEventListener.VoidDelegate)),
  8.     };
复制代码
效果截图比较长且和操作顺序有关,这一部分就不截图了嘎嘎嘎

案例12
这个例子相比之前的那个,看起来就舒服多了
核心代码如下:
  1.     private string script =
  2.         @"                                    
  3.             local GameObject = UnityEngine.GameObject         
  4.             local ParticleSystem = UnityEngine.ParticleSystem            
  5.             local go = GameObject('go')
  6.             go:AddComponent(typeof(ParticleSystem))
  7.             local node = go.transform
  8.             node.position = Vector3.one      
  9.             print('gameObject is: '..tostring(go))   
  10.             GameObject.Destroy(go, 2)                        
  11.         ";
  12.     LuaState lua = null;
  13.     void Start()
  14.     {        
  15.         lua = new LuaState();
  16.         lua.LogGC = true;
  17.         lua.Start();
  18.         LuaBinder.Bind(lua);
  19.         lua.DoString(script);            
  20.     }
复制代码
主要的方法就是
GameObject:AddComponent(typeof(Component)) 在lua中给游戏物体添加组件
GameObject(“游戏物体名”)  在lua中创建新的游戏物体
GameObject.Destroy(游戏对象, 延迟时间)  延时销毁的指定的游戏物体
非常简单,大家随便看看就好了
效果截图如下:


好了,今天就到这里吧!大家下回再见

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 19:36 , Processed in 0.104844 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表