299 lines
7.9 KiB
C#
299 lines
7.9 KiB
C#
// Copyright 2022-2024 Niantic.
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.Events;
|
|
using UnityEngine.InputSystem;
|
|
using UnityEngine.InputSystem.Controls;
|
|
using UnityEngine.InputSystem.LowLevel;
|
|
using UnityEngine.UI;
|
|
using Touch = UnityEngine.InputSystem.EnhancedTouch.Touch;
|
|
using TouchPhase = UnityEngine.TouchPhase;
|
|
|
|
|
|
public class TouchManager : MonoBehaviour
|
|
{
|
|
|
|
[Serializable]
|
|
public class FloatEvent : UnityEvent<float> { };
|
|
|
|
|
|
[Serializable]
|
|
public class Vector2Event : UnityEvent<Vector2> { };
|
|
|
|
[SerializeField] private float _pinchScrollSpeed;
|
|
[SerializeField] private float _mouseScrollSpeed;
|
|
[SerializeField] private float _touchPanSpeed;
|
|
[SerializeField] private float _mousePanSpeed;
|
|
|
|
private LightshipInput _lightshipInput;
|
|
private bool _isPointerDown;
|
|
private bool IsPointerDown
|
|
{
|
|
|
|
get { return _isPointerDown; }
|
|
set
|
|
{
|
|
_isPointerDown = value;
|
|
if ((value == false) && (_IsPanActive))
|
|
{
|
|
_IsPanActive = false;
|
|
PanEnded?.Invoke();
|
|
}
|
|
|
|
}
|
|
}
|
|
private bool _IsPanActive = false;
|
|
private Dictionary<int, TouchState> _activeTouches = new Dictionary<int, TouchState>();
|
|
|
|
|
|
|
|
private float _lastPinchDistance = 0f;
|
|
private bool _resetPinchDistance = false;
|
|
private Coroutine activePinchCoroutine = null;
|
|
|
|
[SerializeField] public FloatEvent PinchEvent = new FloatEvent();
|
|
[SerializeField] public Vector2Event PanEvent = new Vector2Event();
|
|
[SerializeField] public UnityEvent PanEnded = new UnityEvent();
|
|
[SerializeField] public Vector2Event TouchUpEvent = new Vector2Event();
|
|
|
|
|
|
private void Awake()
|
|
{
|
|
_lightshipInput = new LightshipInput();
|
|
|
|
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
_lightshipInput.Enable();
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
_lightshipInput.Disable();
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
_lightshipInput.Input.PrimaryTouch.performed += ctx => PrimaryTouchCallback(ctx);
|
|
_lightshipInput.Input.PrimaryTouch.started += ctx => PrimaryTouchCallback(ctx);
|
|
_lightshipInput.Input.PrimaryTouch.canceled += ctx => PrimaryTouchCallback(ctx);
|
|
|
|
_lightshipInput.Input.SecondaryTouch.performed += ctx => SecondaryTouchCallback(ctx);
|
|
_lightshipInput.Input.SecondaryTouch.started += ctx => SecondaryTouchCallback(ctx);
|
|
_lightshipInput.Input.SecondaryTouch.canceled += ctx => SecondaryTouchCallback(ctx);
|
|
|
|
_lightshipInput.Input.MouseScroll.performed += ctx => MouseScrollCallback(ctx);
|
|
_lightshipInput.Input.MousePan.performed += ctx => MousePanCallback(ctx);
|
|
_lightshipInput.Input.MousePan.canceled += ctx => MousePanCallback(ctx);
|
|
|
|
_lightshipInput.Input.MouseHold.started += ctx => MouseHoldCallback(ctx);
|
|
_lightshipInput.Input.MouseHold.performed += ctx => MouseHoldCallback(ctx);
|
|
_lightshipInput.Input.MouseHold.canceled += ctx => MouseHoldCallback(ctx);
|
|
|
|
}
|
|
|
|
private void MouseHoldCallback(InputAction.CallbackContext ctx)
|
|
{
|
|
switch (ctx.phase)
|
|
{
|
|
case InputActionPhase.Started :
|
|
IsPointerDown = true;
|
|
break;
|
|
case InputActionPhase.Canceled :
|
|
IsPointerDown = false;
|
|
if (!_IsPanActive)
|
|
{
|
|
TouchUpEvent?.Invoke(Mouse.current.position.ReadValue());
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
private void MousePanCallback(InputAction.CallbackContext ctx)
|
|
{
|
|
var mousepan = ctx.ReadValue<Vector2>();
|
|
if (ctx.phase == InputActionPhase.Performed)
|
|
{
|
|
_IsPanActive = true;
|
|
}
|
|
ProcessPan(mousepan * _mousePanSpeed);
|
|
}
|
|
|
|
private void MouseScrollCallback(InputAction.CallbackContext ctx)
|
|
{
|
|
|
|
var mousecroll = ctx.ReadValue<Vector2>();
|
|
ProcessScrollZoom(mousecroll);
|
|
|
|
|
|
}
|
|
|
|
private void SecondaryTouchCallback(InputAction.CallbackContext ctx)
|
|
{
|
|
var touch = ctx.ReadValue<TouchState>();
|
|
PreprocessTouch(touch);
|
|
|
|
}
|
|
|
|
private void PrimaryTouchCallback(InputAction.CallbackContext ctx)
|
|
{
|
|
var touch = ctx.ReadValue<TouchState>();
|
|
PreprocessTouch(touch);
|
|
|
|
}
|
|
|
|
private void PreprocessTouch(TouchState touch)
|
|
{
|
|
|
|
switch (touch.phase)
|
|
{
|
|
case UnityEngine.InputSystem.TouchPhase.Began :
|
|
|
|
_activeTouches.TryAdd(touch.touchId, touch);
|
|
break;
|
|
case UnityEngine.InputSystem.TouchPhase.Ended :
|
|
_activeTouches.Remove(touch.touchId);
|
|
break;
|
|
case UnityEngine.InputSystem.TouchPhase.Canceled :
|
|
_activeTouches.Remove(touch.touchId);
|
|
break;
|
|
case UnityEngine.InputSystem.TouchPhase.None :
|
|
break;
|
|
default :
|
|
_activeTouches[touch.touchId] = touch;
|
|
break;
|
|
}
|
|
|
|
if (_activeTouches.Count > 1)
|
|
{
|
|
if (activePinchCoroutine == null)
|
|
{
|
|
activePinchCoroutine = StartCoroutine(ProcessPinch());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (activePinchCoroutine != null)
|
|
{
|
|
StopCoroutine(activePinchCoroutine);
|
|
activePinchCoroutine = null;
|
|
}
|
|
|
|
if (_activeTouches.Count == 1)
|
|
{
|
|
ProcessTouch();
|
|
}
|
|
else
|
|
{
|
|
IsPointerDown = false;
|
|
}
|
|
}
|
|
|
|
if (IsPointerDown == false)
|
|
if (_IsPanActive)
|
|
{
|
|
_IsPanActive = false;
|
|
PanEnded?.Invoke();
|
|
}
|
|
else
|
|
{
|
|
TouchUpEvent?.Invoke(touch.position);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#region Process Gestures
|
|
|
|
private void ProcessPan(Vector2 delta)
|
|
{
|
|
|
|
PanEvent?.Invoke(delta);
|
|
}
|
|
|
|
|
|
|
|
private IEnumerator ProcessPinch()
|
|
{
|
|
_resetPinchDistance = true;
|
|
while (true)
|
|
{
|
|
|
|
yield return null;
|
|
|
|
var orderedTouches = _activeTouches.OrderBy(x => x.Key).ToArray();
|
|
|
|
var touchOne = orderedTouches[0];
|
|
var touchTwo = orderedTouches[1];
|
|
|
|
var pinchDistance = Vector2.Distance(touchOne.Value.position, touchTwo.Value.position);
|
|
if (_resetPinchDistance)
|
|
{
|
|
_lastPinchDistance = pinchDistance;
|
|
_resetPinchDistance = false;
|
|
}
|
|
|
|
float pinchDelta = (pinchDistance - _lastPinchDistance);
|
|
_lastPinchDistance = pinchDistance;
|
|
|
|
|
|
PinchEvent?.Invoke(pinchDelta * _pinchScrollSpeed);
|
|
}
|
|
}
|
|
|
|
private void ProcessScrollZoom(Vector2 MouseScrollDelta)
|
|
{
|
|
var yScrollDelta = MouseScrollDelta.y * _mouseScrollSpeed;
|
|
PinchEvent?.Invoke(yScrollDelta);
|
|
}
|
|
|
|
private void ProcessMouseMap()
|
|
{
|
|
|
|
}
|
|
|
|
private void ProcessTouch()
|
|
{
|
|
var orderedTouches = _activeTouches.OrderBy(x => x.Key).ToArray();
|
|
var touch = orderedTouches[0].Value;
|
|
switch (touch.phase)
|
|
{
|
|
case UnityEngine.InputSystem.TouchPhase.Began :
|
|
IsPointerDown = true;
|
|
break;
|
|
case UnityEngine.InputSystem.TouchPhase.Ended :
|
|
break;
|
|
case UnityEngine.InputSystem.TouchPhase.Moved:
|
|
_IsPanActive = true;
|
|
var delta = touch.delta;
|
|
if (delta.x + delta.y != 0)
|
|
{
|
|
ProcessPan(delta);
|
|
}
|
|
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|