转载请标明出处: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); }
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; }
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*/