Unity3d中FingerGesture与NGUI的事件响应
发表于2018-12-10
本篇文章的背景是当前项目中同时用到了NGUI与FingerGestures两个插件,但是在按键的时候会出现一些响应问题,针对这个问题,我们来看下解决办法。
如何控制事件响应的顺序?
通常情况下,触发按下事件应当优先响应UI层的事件,首先想到的是调整脚本的执行顺序;然而却发现调整脚本的执行顺便并不会改变同一事件响应两次的情况,由于NGUI与FingerGestures直接由Unity.Touch获取输入事件。
潜在的需求
对于NGUI与FingerGestures响应事件的情况,可以划分为以下三种:
- 仅有NGUI响应事件;
- 仅有FingerGesture响应事件;
- 同时响应
主要解决第一种情况(或者说区分事件响应在NGUI层还是FingerGestures层)
分析NGUI和FingerGestures的代码和文档
在FingerGestures.cs文件中找到如下代码:
#region Global Input Filter /// <summary> /// Return tru /// </summary> /// <param name="fingerIndex">The index of the finger that just touched the screen</param> /// <param name="position">The new finger position if the input is let through</param> /// <returns>True to let the touch go through, or false to block it</returns> public delegate bool GlobalTouchFilterDelegate( int fingerIndex, Vector2 position ); GlobalTouchFilterDelegate globalTouchFilterFunc; /// <summary> /// Can specify a method to selectively prevent new touches from being processed until they are released. /// This can be useful to globally deny gesture events from being fired when above a region of the screen, /// or when the input has been consumed by another input system /// </summary> public static GlobalTouchFilterDelegate GlobalTouchFilter { get { return instance.globalTouchFilterFunc; } set { instance.globalTouchFilterFunc = value; } } protected bool ShouldProcessTouch( int fingerIndex, Vector2 position ) { if( globalTouchFilterFunc != null ) return globalTouchFilterFunc( fingerIndex, position ); return true; }
可以看到FingerGestures已经包含有一个全局的输入过滤器,如若需要过滤FingerGestures对于输入事件的响应,只需实现对应代理即可。
解决方案:
找到一份参考资料:FingerGestures 屏蔽NGUI的方法,其原理是利用Physics.Raycast进行判断,其中我们的需求需要指定碰撞检测的层级,文中需要过滤的层级是NGUI层,注意下文中这段代码的出处是由于那个外国作者的层级关系NGUI为第8个层级,不要盲目照搬代码!
查看自己的项目中NGUI控件所在的层级:
可以看到我的工程中存在一个名为UI的图层,我们将所有的UI调整为该图层,然后进行相应的编码:
/// <summary> /// 设置 FingerGestures 全局输入过滤器 执行接口 /// <returns>True: FingerGestures需要响应输入事件,False: 表示无需响应输入事件</returns> /// </summary> bool FingerGestureShouldProcessTouch(int fingerIndex, Vector2 position) { bool FGpressTouch = true; Ray ray = UICamera.currentCamera.ScreenPointToRay(position); bool hanlded = Physics.Raycast(ray, Mathf.Infinity, 1 << LayerMask.NameToLayer("UI")); ///< 判断UI层是否响应过事件 FGpressTouch = !hanlded; return FGpressTouch; }
对于层级概念的深入理解可以参考:https://docs.unity3d.com/Manual/Layers.html