using System; using UnityEngine; using UnityEngine.Events; namespace KhawajjaGames.Mobile { /// /// Multi-touch Mobile Gesture & Swipe Controller for Unity Android and iOS. /// Handles 4-directional/8-directional swipes, taps, double-taps, and pinch-to-zoom. /// Created by Khawajja Games Studio (https://khawajjagames.com) /// public class MobileSwipeController : MonoBehaviour { public enum SwipeDirection { None, Left, Right, Up, Down, UpLeft, UpRight, DownLeft, DownRight } [Header("Swipe Thresholds")] [Tooltip("Minimum pixel distance required to register a swipe gesture")] public float minSwipeDistance = 50f; [Tooltip("Maximum duration in seconds for a quick flick swipe")] public float maxSwipeTime = 0.5f; [Header("Tap Settings")] public float doubleTapMaxDelay = 0.3f; [Header("Events")] public UnityEvent OnSwipeDetected; public UnityEvent OnTap; public UnityEvent OnDoubleTap; public UnityEvent OnPinchZoom; // Returns zoom delta private Vector2 _fingerDownPosition; private Vector2 _fingerUpPosition; private float _fingerDownTime; private float _lastTapTime; private float _initialPinchDistance; private void Update() { HandleTouchInput(); } private void HandleTouchInput() { // Single Touch Handling (Tap, Double Tap, Swipe) if (Input.touchCount == 1) { Touch touch = Input.GetTouch(0); if (touch.phase == TouchPhase.Began) { _fingerDownPosition = touch.position; _fingerUpPosition = touch.position; _fingerDownTime = Time.time; } else if (touch.phase == TouchPhase.Moved) { _fingerUpPosition = touch.position; } else if (touch.phase == TouchPhase.Ended) { _fingerUpPosition = touch.position; float duration = Time.time - _fingerDownTime; float distance = Vector2.Distance(_fingerDownPosition, _fingerUpPosition); if (distance >= minSwipeDistance && duration <= maxSwipeTime) { DetectSwipeDirection(); } else if (distance < minSwipeDistance) { DetectTap(); } } } // Dual Touch Handling (Pinch to Zoom) else if (Input.touchCount == 2) { Touch touchZero = Input.GetTouch(0); Touch touchOne = Input.GetTouch(1); Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition; Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition; float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude; float touchDeltaMag = (touchZero.position - touchOne.position).magnitude; float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag; OnPinchZoom?.Invoke(deltaMagnitudeDiff); } } private void DetectSwipeDirection() { Vector2 direction = _fingerUpPosition - _fingerDownPosition; float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg; if (angle < 0) angle += 360f; SwipeDirection swipe = SwipeDirection.None; if (angle >= 337.5f || angle < 22.5f) swipe = SwipeDirection.Right; else if (angle >= 22.5f && angle < 67.5f) swipe = SwipeDirection.UpRight; else if (angle >= 67.5f && angle < 112.5f) swipe = SwipeDirection.Up; else if (angle >= 112.5f && angle < 157.5f) swipe = SwipeDirection.UpLeft; else if (angle >= 157.5f && angle < 202.5f) swipe = SwipeDirection.Left; else if (angle >= 202.5f && angle < 247.5f) swipe = SwipeDirection.DownLeft; else if (angle >= 247.5f && angle < 292.5f) swipe = SwipeDirection.Down; else if (angle >= 292.5f && angle < 337.5f) swipe = SwipeDirection.DownRight; OnSwipeDetected?.Invoke(swipe); } private void DetectTap() { float timeSinceLastTap = Time.time - _lastTapTime; if (timeSinceLastTap <= doubleTapMaxDelay) { OnDoubleTap?.Invoke(); _lastTapTime = 0f; } else { OnTap?.Invoke(); _lastTapTime = Time.time; } } } }