使用EasyTouch, 摇杆在Dynamic模式下,点击UI控件也会弹出的问题解决

转载请标明出处:http://blog.csdn.net/u013015161/article/details/46495561

使用EasyTouch插件,其提供的虚拟摇杆有一个Dynamic stick属性, 勾选之后, 只有当鼠标或者手指触摸到屏幕, 才会在手指或鼠标触碰的位置出现虚拟摇杆。

当场景中存在UI控件时,会出现以下场景。


很显然 , 当玩家点击按钮的时候依然弹出虚拟摇杆是不合理的。


解决这个问题,首先得看虚拟摇杆何时会弹出, 在EasyJoystick.cs中可以找到以下代码:

if ((showZone && areaTexture!=null && !dynamicJoystick) || (showZone && dynamicJoystick && virtualJoystick && areaTexture!=null) 
				|| (dynamicJoystick && Application.isEditor && !Application.isPlaying)){
				if (isActivated){
					GUI.color = areaColor;
					
					if (Application.isPlaying && !dynamicJoystick){
						EasyTouch.RemoveReservedArea( areaRect );
						EasyTouch.AddReservedArea( areaRect );
					}
				}
				else{
					GUI.color = new Color(areaColor.r,areaColor.g,areaColor.b,0.2f);	
					if (Application.isPlaying && !dynamicJoystick){
						EasyTouch.RemoveReservedArea( areaRect );	
					}
				}		
				
				if (showDebugRadius && Application.isEditor){
					GUI.Box( areaRect,"");				
				}

                GUI.DrawTexture( areaRect, areaTexture,ScaleMode.StretchToFill,true);
			}

可以看到,当摇杆模式为dynamic时, 要判断virtualJoystick值。 于是跟踪该变量,可以找到以下代码 (起始行:1386)

void On_TouchStart(Gesture gesture){
					
		if ((!gesture.isHoverReservedArea && dynamicJoystick) || !dynamicJoystick){

			if (isActivated){
				if (!dynamicJoystick){
				
					Vector2 center = new Vector2( (anchorPosition.x+joystickCenter.x) * VirtualScreen.xRatio , (VirtualScreen.height-anchorPosition.y - joystickCenter.y) * VirtualScreen.yRatio);
					
					if ((gesture.position - center).sqrMagnitude < (zoneRadius *VirtualScreen.xRatio )*(zoneRadius *VirtualScreen.xRatio )){
						joystickIndex = gesture.fingerIndex;
						CreateEvent(MessageName.On_JoystickTouchStart);
					}			
				}
				else{
					if (!virtualJoystick){
						
						#region area restriction
						<span style="color:#ff0000;">switch (area){
							// full
							case DynamicArea.FullScreen:
								virtualJoystick = true;	;
								break;
							// bottom
							case DynamicArea.Bottom:
								if (gesture.position.y< Screen.height/2){
									virtualJoystick = true;	
								}
								break;
							// top
							case DynamicArea.Top:
								if (gesture.position.y> Screen.height/2){
									virtualJoystick = true;	
								}
								break;
							// Right
							case DynamicArea.Right:
								if (gesture.position.x> Screen.width/2){
									virtualJoystick = true;	
								}
								break;
							// Left
							case DynamicArea.Left:
								if (gesture.position.x< Screen.width/2){
									virtualJoystick = true;	
								}
								break;				
							
							// top Right
							case DynamicArea.TopRight:
								if (gesture.position.y> Screen.height/2 && gesture.position.x> Screen.width/2){
									virtualJoystick = true;	
								}
								break;	
							// top Left
							case DynamicArea.TopLeft:
								if (gesture.position.y> Screen.height/2 && gesture.position.x< Screen.width/2){
									virtualJoystick = true;	
								}
								break;					
							// bottom Right
							case DynamicArea.BottomRight:
								if (gesture.position.y< Screen.height/2 && gesture.position.x> Screen.width/2){
									virtualJoystick = true;	
								}
								break;					
							// bottom left
							case DynamicArea.BottomLeft:
								if (gesture.position.y< Screen.height/2 && gesture.position.x< Screen.width/2){
									virtualJoystick = true;	
								}
							break;							
						}		</span>		
						#endregion
						
						if (virtualJoystick){
							joystickCenter =new Vector2(gesture.position.x/VirtualScreen.xRatio,  VirtualScreen.height - gesture.position.y/VirtualScreen.yRatio);
							JoyAnchor = JoystickAnchor.None;
							joystickIndex = gesture.fingerIndex;
						}	
					}
				}
			
			}
		}
	}
可以看到,在touch时间发生时, 会判断触点是否在目标区域(分上、下、左、右屏等,可以在joystick的属性面板调整)来决定是否出现虚拟摇杆(即virtualJoystick的值)。

所以如果要防止开头描述的问题,只需要在virtualJoystick赋值为true之前判断以下当前是否触摸或点击在UGUI上即可。

实现该判断,常见的方法是判断EventSystem.current.IsPointerOverGameObject()的返回值。但该值在触屏设备上总是返回false。

Unity官方论坛上有人整理了一份代码(点击进入相关帖子),pc和触屏设备都可以正常检测代码,代码如下

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class IPointerOverUI {
 
        private static IPointerOverUI instance = new IPointerOverUI();
        public static IPointerOverUI Instance
        {
                get{
                        return instance;
                }
        }
 
        public bool IsPointerOverUIObject(Canvas canvas, Vector2 screenPosition) {
                PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
                eventDataCurrentPosition.position = screenPosition;
                 
                GraphicRaycaster uiRaycaster = canvas.gameObject.GetComponent<GraphicRaycaster>();
                List<RaycastResult> results = new List<RaycastResult>();
                uiRaycaster.Raycast(eventDataCurrentPosition, results);
                return results.Count > 0;
        }
 
        public bool IsPointerOverUIObject() {
                PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
                eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
                 
                List<RaycastResult> results = new List<RaycastResult>();
                EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
                return results.Count > 0;
        }
}
可以看到, 2个方法虽然参数不同,但主要思路都是通过发射射线进行判断, 如果射线碰撞到了UI控件,则判定在触碰UGUI控件上。经检验和分析,第一种方法需要传入特定canvas, 而第二种是以Input.mousePosition作为触点的位置, 在多点触控时, 显然不可能每个点的位置都用该值描述(通常该值仅代表第一个触点的位置)。于是自己新增一个重载函数:

public bool IsPointerOverUIObject(float x, float y) {
        PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
        eventDataCurrentPosition.position = new Vector2 (x, y);
        
        List<RaycastResult> results = new List<RaycastResult>();
        EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
        return results.Count > 0;
    }

在EasyJoystick.cs中调用如下(起始行:1386):

void On_TouchStart(Gesture gesture){
        /*added by lankton  2015 6 14*/
        if (IPointerOverUI.Instance.IsPointerOverUIObject (gesture.position.x, gesture.position.y)) 
        { /*点击在UGUI上 则不处理EasyTouch的触摸事件*/
            return;
        }
        /*end*/


这样,对EasyTouch插件进行了简单的补充, UGUI和EasyTouch的虚拟摇杆就能正常的同时使用了:

<Unity UGUI><EasyTouch> 使用EasyTouch, 摇杆在Dynamic模式下,点击UI控件也会弹出的问题解决_第1张图片

你可能感兴趣的:(unity,UGUI,EasyTouch)