c1_unity/Assets/Scripts/Common/Touch/BFTouchManager.cs
2023-04-03 11:04:31 +08:00

443 lines
15 KiB
C#

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<TouchEventType, BFFinger> onFinger;
public BFEvent<List<BFFinger>> onGesture;
public List<BFFinger> fingers = new List<BFFinger>(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<BFFinger> inactiveFingers = new List<BFFinger>(10);
List<BFFinger> filteredFingers = new List<BFFinger>(10);
int highestMounseButton = 7;
List<RaycastResult> tempRaycastResults = new List<RaycastResult>(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<TouchEventType, BFFinger>(20);
onGesture = new BFEvent<List<BFFinger>>(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<RaycastResult> 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<RaycastResult> 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<BFFinger> 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;
}
}
}