Unity3D热更新之LuaFramework篇[05]--Lua脚本调用c#以及如何在Lua中使用Dotween Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法

 在上一篇文章 Unity3D热更新之LuaFramework篇[04]--自定义UI监听方法 中,我对LuaBehaviour脚本进行了扩展,添加了两个新的UI监听方法,也提到最好能单写一个脚本处理此事。本篇文章就来继续这个工做。html

 

从Lua中调用C#代码

一、建立UI监听脚本

 打开以前的工程,在Assets/LuaFrameworks/Scripts/Common下,建立一个UIEventEx.cs脚本,将LuaBehaviour.cs中的AddButtonClick以及AddInputFieldEndEditHandler方法迁移过来,并扩展了一些其它方法,代码以下:git

  1 using LuaInterface;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using UnityEngine;
  5 using UnityEngine.EventSystems;
  6 using UnityEngine.UI;
  7 
  8 /// <summary>
  9 /// 自定义的添加UI监听的方法,能够用lua中调用以作事件绑定
 10 /// </summary>
 11 public class UIEventEx {
 12     //添加监听
 13     public static void AddButtonClick(GameObject go, LuaFunction luafunc)
 14     {
 15         if (go == null || luafunc == null)
 16             return;
 17 
 18         Button btn = go.GetComponent<Button>();
 19         if (btn == null)
 20             return;
 21 
 22         btn.onClick.AddListener
 23         (
 24             delegate ()
 25             {
 26                 luafunc.Call(go);
 27             }
 28         );
 29     }
 30 
 31     //添加监听(外带数据中转功能)
 32     public static void AddButtonClick(GameObject go, LuaFunction luafunc, LuaTable luatable)
 33     {
 34         if (go == null || luafunc == null)
 35             return;
 36 
 37         Button btn = go.GetComponent<Button>();
 38         if (btn == null)
 39             return;
 40 
 41         btn.onClick.AddListener
 42         (
 43             delegate ()
 44             {
 45                 luafunc.Call(go, luatable);
 46             }
 47         );
 48     }
 49 
 50     /// <summary>
 51     /// 给Toggle组件添加监听
 52     /// </summary>
 53     public static void AddToggle(GameObject go, LuaFunction luafunc, LuaTable luatable)
 54     {
 55         if (go == null || luafunc == null) return;
 56 
 57         Toggle toggle = go.GetComponent<Toggle>();
 58 
 59         if (toggle == null) return;
 60 
 61         go.GetComponent<Toggle>().onValueChanged.AddListener(
 62             delegate (bool select) {
 63                 luafunc.Call(luatable, select);
 64             }
 65         );
 66     }
 67 
 68 
 69     /// <summary>
 70     /// 给Toggle组件添加监听
 71     /// </summary>
 72     public static void AddToggle(GameObject go, LuaFunction luafunc)
 73     {
 74         if (go == null || luafunc == null) return;
 75 
 76         Toggle toggle = go.GetComponent<Toggle>();
 77 
 78         if (toggle == null) return;
 79 
 80         go.GetComponent<Toggle>().onValueChanged.AddListener(
 81             delegate (bool select) {
 82                 luafunc.Call(select);
 83             }
 84         );
 85     }
 86 
 87     //给输入组件(InputField)添加结束编辑(OnEndEdit)监听
 88     public static void AddInputFieldEndEditHandler(GameObject go, LuaFunction luafunc)
 89     {
 90         if (go == null || luafunc == null) return;
 91 
 92         InputField input = go.GetComponent<InputField>();
 93 
 94         if (input == null)
 95         {
 96             Debug.LogError(go.name + "找不到InputField组件");
 97             return;
 98         }
 99 
100         go.GetComponent<InputField>().onEndEdit.AddListener(
101             delegate (string text) {
102                 luafunc.Call(text);
103             }
104         );
105     }
106 
107     /// <summary>
108     /// 添加对光标按下|抬起事件的支持
109     /// </summary>
110     /// <param name="go">目标对象</param>
111     /// <param name="luafunc">按下事件</param>
112     /// <param name="luafunc2">抬起事件</param>
113     public static void AddPointerDownUpSupport(GameObject go, LuaFunction luafunc, LuaFunction luafunc2)
114     {
115         if (go == null) return;
116 
117         EventsSupport es = go.AddComponent<EventsSupport>();
118 
119         es.InitDownUpHandler((PointerEventData pointerEventData) => {
120             if (luafunc != null)
121             {
122                 luafunc.Call(go, pointerEventData);
123             }
124 
125         }, (PointerEventData pointerEventData) => {
126             if (luafunc2 != null)
127             {
128                 luafunc2.Call(go, pointerEventData);
129             }
130         });
131     }
132 
133     /// <summary>
134     /// 给Slider组件添加onValueChanged事件
135     /// </summary>
136     /// <param name="go"></param>
137     /// <param name="luafunc"></param>
138     public static void AddSliderOnChangeEvent(GameObject go, LuaFunction luafunc)
139     {
140         if (go == null || luafunc == null) return;
141 
142         Slider component = go.GetComponent<Slider>();
143 
144         if (component == null)
145         {
146             Debug.LogError(go.name + "找不到Slider组件");
147             return;
148         }
149 
150         go.GetComponent<Slider>().onValueChanged.AddListener(
151             delegate (float val) {
152                 luafunc.Call(val);
153             }
154         );
155     }
156 
157     //清除监听
158     public static void ClearButtonClick(GameObject go)
159     {
160         if (go == null)
161             return;
162 
163         Button btn = go.GetComponent<Button>();
164         if (btn == null)
165             return;
166 
167         btn.onClick.RemoveAllListeners();
168     }
169 
170 }
UIEventEx.cs

在Assets/LuaFrameworks/Scripts/Common下,建立一个EventsSupport.cs脚本,该脚本是一个实现了IPointerDownHandler, IPointerUpHandler等接口的类,用于在Lua中检测鼠标输入(鼠标点击,抬起、按下等功能),配合UIEventEx.cs中的AddPointerDownUpSupport方法使用。其代码以下:c#

 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using UnityEngine;
 5 using UnityEngine.EventSystems;
 6 
 7 /*  其它事件可根据须要在此类中实现
 8     IPointerEnterHandler - OnPointerEnter - Called when a pointer enters the object
 9     IPointerExitHandler - OnPointerExit - Called when a pointer exits the object
10     IPointerDownHandler - OnPointerDown - Called when a pointer is pressed on the object
11     IPointerUpHandler - OnPointerUp - Called when a pointer is released (called on the original the pressed object)
12     IPointerClickHandler - OnPointerClick - Called when a pointer is pressed and released on the same object
13     IInitializePotentialDragHandler - OnInitializePotentialDrag - Called when a drag target is found, can be used to initialise values
14     IBeginDragHandler - OnBeginDrag - Called on the drag object when dragging is about to begin
15     IDragHandler - OnDrag - Called on the drag object when a drag is happening
16     IEndDragHandler - OnEndDrag - Called on the drag object when a drag finishes
17     IDropHandler - OnDrop - Called on the object where a drag finishes
18     IScrollHandler - OnScroll - Called when a mouse wheel scrolls
19     IUpdateSelectedHandler - OnUpdateSelected - Called on the selected object each tick
20     ISelectHandler - OnSelect - Called when the object becomes the selected object
21     IDeselectHandler - OnDeselect - Called on the selected object becomes deselected
22     IMoveHandler - OnMove - Called when a move event occurs (left, right, up, down, ect)
23     ISubmitHandler - OnSubmit - Called when the submit button is pressed
24     ICancelHandler - OnCancel - Called when the cancel button is pressed
25  */
26 
27 /// <summary>
28 /// unity事件支持(本类用于实现Unity中的各类事件,借给Lua调用)
29 /// </summary>
30 public class EventsSupport : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
31 {
32     Action<PointerEventData> onPointerDownHandler = null;
33     Action<PointerEventData> onPointerUpHandler = null;
34 
35     public void InitDownUpHandler (Action<PointerEventData> downHandler, Action<PointerEventData> upHandler)
36     {
37         onPointerDownHandler = downHandler;
38         onPointerUpHandler = upHandler;
39     }
40 
41     public void OnPointerDown(PointerEventData pointerEventData)
42     {
43         //Output the name of the GameObject that is being clicked
44         //Debug.Log("[" + name + "] Game Object Click in Progress");
45         
46         if (onPointerDownHandler != null) {
47             onPointerDownHandler(pointerEventData);
48         }
49     }
50 
51     //Detect if clicks are no longer registering
52     public void OnPointerUp(PointerEventData pointerEventData)
53     {
54         //Debug.Log("[" + name + "] No longer being clicked");
55         if (onPointerUpHandler != null)
56         {
57             onPointerUpHandler(pointerEventData);
58         }
59     }
60 }
EventsSupport.cs

EventsSupport.cs脚本须要挂在待检测输入的Game Object上。app

 

二、使用脚本

这里仍是以上一篇文章写的登录界面为例,以前咱们是经过LuaBehaviour给Button、Toggle以及InputField添加的监听函数,如今将相应的用法直接替换掉。框架

替换前:ide

替换后:函数

 

而后运行,看是否生效。oop

......post

运行结果,报错了,提示全局变量 UIEventEx为nil(就是这个变量不存在的意思)动画

  看来这样想固然的方法是行不通了,咱们不能建立一个C#脚本,而后在Lua中直接使用它。

 

三、C#类导出

在上一步中,咱们发现没法直接在Lua中使用建立的C#脚本。经过查阅资料了解到,对自定义的c#类,若是想在Lua中使用的话,须要作一个导出操做才行。

ToLua的官方git上也有相关的说明:

跟着说明操做:

1)找到Assets\LuaFramework\Editor\下的CustomSettings.cs脚本; 

2)在CustomSettings的60 行左右照例添加一个导出语句"_GT(typeof(UIEventEx)),";

 

3)点击Lua/Generate All菜单,等到日志打印 Generate LuaBinder over !字样时,代表Generate操做已经完成了。

此时查看Assets\LuaFramework\ToLua\Source\Generate,能找到一个叫UIEventExWrap的cs文件,这个就是UIEventEx的导出类。

 

4)从新运行Unity,已经再也不报错了,点击Button、Toggle、在InputField中输入字符,功能都和以前使用LuaBehaviour时一致。

 

总结

若是想在Lua中使用自定义的c#类,须要4个步骤:

1)建立c#脚本;

2)在CustomSetting.cs中添加导出语句;

3)点击Lua/Generate All菜单;

4)在Lua中以全局变量的形式直接使用;

 

这里涉及的转化过程是这样的:

1)UIEventEx脚本经过Lua/Generate All菜单生成UIEventWrap脚本;

2)UIEventWrap脚本通过ToLua的做用,最终成为Lua中的一个全局变量UIEventEx

 

在以前的文章中咱们曾直接使用Lua/Generate All菜单而未作解释,那么如今你应该明白它的作用是什么了。

至于ToLua怎么把一个XxxWrap转换为Lua中的全局变量,就不是本文能讲得清的了(你能够本身作弄清楚);

 

怎么在Lua中使用Dotween

Dotween做为一款很是优秀的缓动动画插件,基本上快成为Unity的标配了。而若是想把全部的UI逻辑所有Lua化,那么在Lua中使用Dotween就是必须的了。

根据前边的经验,Dotween相关的类对于ToLua来讲,就是自定义类,想要在Lua中使用,就必须作导出操做。

那么就有如下步骤:

1)给项目导入一个Dotween插件;

2)导出Dotween相关类;

第二步就是要整理Dotween相关的类,而后一个个写导出语句,这不是一个简单的活儿。

不过没必要担忧,ToLua已经帮咱们作好了。

打开Assets\LuaFramework\Editor\下的CustomSettings.cs脚本,在70~100行左右,能看到Dotween相关类的导出语句,不过因为未检测到USING_DOTWEENING宏定义的缘由,这一段代码并未生效。

 3)使用宏定义USING_DOTWEENING

 一个简单的定义宏的办法是在脚本头部加入 #define USING_DOTWEENING语句,以下图

另一个办法是在PlayerSettings的Scripting Define Symbols*下添加相应的宏,以下图: 

其中ASYNC_MOD是以前有的,两个宏之间用分号隔开,输入USING_DOTWEENING 要回车一次,让脚本从新编译。

这里使用第一种办法。

定义了宏以后,Dotween相关类的导出语句就生效了,而后要执行一次Lua/Generate All。

4)在Lua中做用Dotween

 以登录界面的登录按钮为例,在LoginPanel.lua脚本中添加以下的Dotween使用方法。 

而后运行,能看到动画已经生效了(移动及循环都没问题),不过最后的回调没执行。

看日志有一个报错,说的是TweenCallback未注册。这个就是OnComplete回调未执行的缘由。

 TweenCallback是一个委托类型,根据此前了知识,委托类型也须要在CustomSetting中指定位置注册。

打开CustomSettings脚本,在40~50行左右的位置,添加TweenCallback的导出语句"_DT(typeof(DG.Tweening.TweenCallback)),",以下图所示:

以后从新执行Lua/Generate All菜单(若是有报错,可先执行一次Clear再执行Generate All)。

如今将循环次数改成1,从新运行。

能看到动画中止后,指定的日志已经输出。

在Lua中使用用Dotween,就是这样一个步骤。

 

 有一点要注意的是,在Lua中的代码提示是很不健全的,特别是在调用用C#脚本的时候。

这里写Dotween动画的代码就是全靠经验,若是不熟的话,也能够先用C#写一遍,再搬到Lua中改造。

 

怎么从C#中调用Lua脚本

文章的前半部分介绍了Lua中调用c#的方法,那么相应的如何从c#中调用Lua也有必要了解一下。

c#调用Lua是比较少的一个操做,基本上就在框架(LuaFramework)初始化的时候有用到。这里不作详细案例,只讲一下了解方式。

方式1:

ToLua的Examples, 03_CallLuaFunction,这个脚本详细讲述了c#调用Lua的过程。

方式2:

LuaFramework的LuaManager类,这个脚本里有详细的调用Main.Lua的过程。

 

 

后记 

一个疑问:

在写Lua的Dotween代码的时候,使用DOLocalMove、SetLoops和OnComplete都是用冒号:的方式,实际上这三个都是static方法,这有违于上一篇文章中总结的静态方法用点号,成员方法用冒号的规则。

暂不知道缘由,若是你知道,还请留言指教。

 

------------------------------------

疑问已解决,答案在1楼,感谢 @ 马三小伙儿 大佬的解答

相关文章
相关标签/搜索