using System; using UnityEngine; using System.Collections.Generic; using UnityEngine.EventSystems; namespace BF { public enum TouchEventType { Down = 0, Touching, Up, Hit, Slide, Dead, } public class BFTouchManager : ManagerBase { static BFTouchManager instance; public static BFTouchManager Create() { BFLog.LogAssert(instance == null, "This method only allows BFMain to call once"); instance = new BFTouchManager(); instance.Init(); return instance; } public BFEvent onFinger; public BFEvent> onGesture; public List fingers = new List(10); public float hitThresholdTime = 0.2f; // 点击触发的最大触摸时间间隔 public float slideThresholdPixels = 50.0f; // 滑动拉起至少需要的滑动距离 public LayerMask targetLayers = (1 << 17) | (1 << 13) | (1 << 14) | (1 << 5); // 事件接收layer (地宫,CityBuilding,CityGroundEvent,UI) public bool recordFingers = false; // 是否记录手指快照 public float recordThresholdPixels = 5.0f; // 记录快照阀值 public float recordTimeLimit = 10.0f; // 快照清理时间 public bool simulateMultiFingers = true; public int maxFinger = 2; // 多指触碰最多手指数量 List inactiveFingers = new List(10); List filteredFingers = new List(10); int highestMounseButton = 7; List tempRaycastResults = new List(10); PointerEventData tempPointerEventData; EventSystem tempEventSystem; bool guideMask = false; // 是否屏蔽手势 // Vector2 pivot = new Vector2(0.5f, 0.5f); // KeyCode pinchTwistKey = KeyCode.LeftAlt; // KeyCode movePivotKey = KeyCode.RightAlt; //设置手势是否有效 public void SetGuideMask(bool mask) { guideMask = mask; } bool AnyMouseButtonSet { get { for (var i = 0; i < highestMounseButton; i++) { if (Input.GetMouseButton(i) == true) { return true; } } return false; } } private BFTouchManager() { } public override void Init() { onFinger = new BFEvent(20); onGesture = new BFEvent>(20); } public override void Destroy() { instance = null; } public Transform RaycastFindTrans(Vector2 screenPosition) { var results = RaycastFind(screenPosition); if (results.Count > 0) { return results[0].gameObject.transform; } return null; } public bool PointOverTargetLayer(Vector2 screenPosition) { return RaycastFind(screenPosition).Count > 0; } public bool PointOverLayer(Vector2 screenPosition, LayerMask layer) { return RaycastFind(screenPosition, layer).Count > 0; } public List RaycastFind(Vector2 screenPosition) { return RaycastFind(screenPosition, targetLayers); } public bool RaycastResultContains(Vector2 screenPosition, Transform transform) { var raycastResult = RaycastFind(screenPosition); for (var i = 0; i < raycastResult.Count; i++) { if (raycastResult[i].gameObject.transform == transform) { return true; } } return false; } public List RaycastFind(Vector2 screenPosition, LayerMask layerMask) { tempRaycastResults.Clear(); var currentEventSystem = EventSystem.current; if (currentEventSystem != null) { if (currentEventSystem != tempEventSystem) { tempEventSystem = currentEventSystem; if (tempPointerEventData == null) { tempPointerEventData = new PointerEventData(tempEventSystem); } else { tempPointerEventData.Reset(); } } tempPointerEventData.position = screenPosition; currentEventSystem.RaycastAll(tempPointerEventData, tempRaycastResults); if (tempRaycastResults.Count > 0) { for (int i = tempRaycastResults.Count - 1; i >= 0; i--) { var raycastResult = tempRaycastResults[i]; var raycastLayer = 1 << raycastResult.gameObject.layer; if ((raycastLayer & layerMask) == 0) { tempRaycastResults.RemoveAt(i); } } } } else { Debug.LogError("Failed to RaycastGui because your scene doesn't have an event system! To add one, go to: GameObject/UI/EventSystem"); } return tempRaycastResults; } public List GetFingers(bool ignoreIfStartedOverGui, bool ignoreIfOverGui, int fingerCount = 0) { filteredFingers.Clear(); for (int i = 0; i < fingers.Count; i++) { var finger = fingers[i]; if (ignoreIfStartedOverGui == true && finger.startOverTargetLayer == true) { continue; } if (ignoreIfOverGui == true && finger.IsOverTargetLayer == true) { continue; } filteredFingers.Add(finger); } if (fingerCount > 0 && filteredFingers.Count != fingerCount) { filteredFingers.Clear(); return filteredFingers; } return filteredFingers; } public override void Update() { BeginFingers(); PollFingers(); EndFingers(); UpdateEvents(); } void BeginFingers() { for (int i = inactiveFingers.Count - 1; i >= 0; i--) { var inactiveFinger = inactiveFingers[i]; inactiveFinger.age += Time.unscaledDeltaTime; if (inactiveFinger.dead == false && inactiveFinger.age > hitThresholdTime) { inactiveFinger.dead = true; onFinger.Invoke(TouchEventType.Dead, inactiveFinger); } } for (int i = fingers.Count - 1; i >= 0; i--) { var finger = fingers[i]; if (finger.Up == true) { fingers.RemoveAt(i); inactiveFingers.Add(finger); finger.age = 0.0f; finger.ClearSnapshots(); } else { finger.lastTouching = finger.touching; finger.lastPressure = finger.pressure; finger.lastScreenPos = finger.curScreenPos; finger.touching = false; finger.hit = false; finger.slide = false; finger.cantTriggerHit = false; } } } void PollFingers() { if (Input.touchCount > 0) { for (var i = 0; i < Input.touchCount; i++) { var touch = Input.GetTouch(i); if (touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved) { AddFinger(touch.fingerId, touch.position, touch.pressure); } } } else if (AnyMouseButtonSet) { var screen = new Rect(0, 0, Screen.width, Screen.height); var mousePosition = Input.mousePosition; if (screen.Contains(mousePosition)) { AddFinger(-1, mousePosition, 1.0f); // if (simulateMultiFingers) // { // if (Input.GetKey(movePivotKey)) // { // pivot.x = mousePosition.x / Screen.width; // pivot.y = mousePosition.y / Screen.height; // } // if (Input.GetKey(pinchTwistKey)) // { // Vector2 center = new Vector2(Screen.width * pivot.x, Screen.height * pivot.y); // AddFinger(-2, center - (mousePosition - center), 1.0f); // } // } } } else if (Input.mouseScrollDelta.magnitude > 0) { var screen = new Rect(0, 0, Screen.width, Screen.height); var mousePosition = Input.mousePosition; if (screen.Contains(mousePosition)) { AddFinger(-1, mousePosition, 1.0f); AddFinger(-2, mousePosition, 1.0f); } } } void EndFingers() { for (var i = fingers.Count - 1; i >= 0; i--) { var finger = fingers[i]; finger.cantTriggerHit = finger.cantTriggerHit || Input.touchCount > 1; if (finger.Up) { if (finger.age <= hitThresholdTime) { if (finger.SlideScreenDelta.magnitude < slideThresholdPixels) { finger.hit = true; finger.hitCount += 1; } else { finger.hitCount = 0; finger.slide = true; } } else { finger.hitCount = 0; } } else if (!finger.Down) { finger.age += Time.unscaledDeltaTime; } } } void UpdateEvents() { //如果处于屏蔽阶段 不处理 if (guideMask) { return; } var fingerCount = fingers.Count; if (fingerCount > 0) { for (var i = 0; i < fingerCount; i++) { var finger = fingers[i]; if (finger.hit) onFinger.Invoke(TouchEventType.Hit, finger); if (finger.slide) onFinger.Invoke(TouchEventType.Slide, finger); if (finger.Down) onFinger.Invoke(TouchEventType.Down, finger); if (finger.touching) onFinger.Invoke(TouchEventType.Touching, finger); if (finger.Up) onFinger.Invoke(TouchEventType.Up, finger); } if (onGesture != null) { filteredFingers.Clear(); filteredFingers.AddRange(fingers); onGesture.Invoke(filteredFingers); } } } void AddFinger(int index, Vector2 screenPos, float pressure) { var finger = FindFinger(index); if (finger == null) { if (fingers.Count >= maxFinger) { return; } var inactiveIndex = FindInactiveFingerIndex(index); if (inactiveIndex >= 0) { finger = inactiveFingers[inactiveIndex]; inactiveFingers.RemoveAt(inactiveIndex); if (finger.age > hitThresholdTime) { finger.hitCount = 0; } finger.age = 0.0f; finger.touching = false; finger.lastTouching = false; finger.hit = false; finger.slide = false; finger.dead = false; } else { finger = new BFFinger(); finger.index = index; } finger.startScreenPos = screenPos; finger.lastScreenPos = screenPos; finger.lastPressure = pressure; finger.startTargetTrans = RaycastFindTrans(screenPos); finger.startOverTargetLayer = finger.startTargetTrans != null; fingers.Add(finger); } finger.touching = true; finger.curScreenPos = screenPos; finger.pressure = pressure; if (recordFingers) { if (recordTimeLimit > 0.0f) { if (finger.SnapshotDuration > recordTimeLimit) { int removeCount = BFFingerSnapshot.GetLowerIndex(finger.snapshotList, finger.age - recordTimeLimit); finger.ClearSnapshots(removeCount); } } if (recordThresholdPixels > 0.0f) { if (finger.snapshotList.Count == 0 || finger.LastSnapshotScreenDelta.magnitude >= recordThresholdPixels) { finger.RecordSnapshot(); } } else { finger.RecordSnapshot(); } } } BFFinger FindFinger(int index) { for (var i = fingers.Count - 1; i >= 0; i--) { var finger = fingers[i]; if (finger.index == index) { return finger; } } return null; } int FindInactiveFingerIndex(int index) { for (var i = inactiveFingers.Count - 1; i >= 0; i--) { if (inactiveFingers[i].index == index) { return i; } } return -1; } } }