using UnityEngine; using System.Collections; using UnityEngine.UI; using UnityEngine.Events; using UnityEngine.EventSystems; #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER using UnityEngine.InputSystem; #endif namespace MoreMountains.Tools { /// /// The possible directions a swipe can have /// public enum MMPossibleSwipeDirections { Up, Down, Left, Right } [System.Serializable] public class SwipeEvent : UnityEvent {} /// /// An event usually triggered when a swipe happens. It contains the swipe "base" direction, and detailed information if needed (angle, length, origin and destination /// public struct MMSwipeEvent { public MMPossibleSwipeDirections SwipeDirection; public float SwipeAngle; public float SwipeLength; public Vector2 SwipeOrigin; public Vector2 SwipeDestination; public float SwipeDuration; /// /// Initializes a new instance of the struct. /// /// Direction. /// Angle. /// Length. /// Origin. /// Destination. public MMSwipeEvent(MMPossibleSwipeDirections direction, float angle, float length, Vector2 origin, Vector2 destination, float swipeDuration) { SwipeDirection = direction; SwipeAngle = angle; SwipeLength = length; SwipeOrigin = origin; SwipeDestination = destination; SwipeDuration = swipeDuration; } static MMSwipeEvent e; public static void Trigger(MMPossibleSwipeDirections direction, float angle, float length, Vector2 origin, Vector2 destination, float swipeDuration) { e.SwipeDirection = direction; e.SwipeAngle = angle; e.SwipeLength = length; e.SwipeOrigin = origin; e.SwipeDestination = destination; e.SwipeDuration = swipeDuration; MMEventManager.TriggerEvent(e); } } /// /// Add a swipe manager to your scene, and it'll trigger MMSwipeEvents everytime a swipe happens. From its inspector you can determine the minimal length of a swipe. Shorter swipes will be ignored /// [RequireComponent(typeof(RectTransform))] [AddComponentMenu("More Mountains/Tools/Controls/MMSwipeZone")] public class MMSwipeZone : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler, IPointerEnterHandler { /// the minimal length of a swipe [Tooltip("the minimal length of a swipe")] public float MinimalSwipeLength = 50f; /// the maximum press length of a swipe [Tooltip("the maximum press length of a swipe")] public float MaximumPressLength = 10f; /// The method(s) to call when the zone is swiped [Tooltip("The method(s) to call when the zone is swiped")] public SwipeEvent ZoneSwiped; /// The method(s) to call while the zone is being pressed [Tooltip("The method(s) to call while the zone is being pressed")] public UnityEvent ZonePressed; [Header("Mouse Mode")] [MMInformation("If you set this to true, you'll need to actually press the button for it to be triggered, otherwise a simple hover will trigger it (better for touch input).", MMInformationAttribute.InformationType.Info,false)] /// If you set this to true, you'll need to actually press the button for it to be triggered, otherwise a simple hover will trigger it (better for touch input). [Tooltip("If you set this to true, you'll need to actually press the button for it to be triggered, otherwise a simple hover will trigger it (better for touch input).")] public bool MouseMode = false; protected Vector2 _firstTouchPosition; protected float _angle; protected float _length; protected Vector2 _destination; protected Vector2 _deltaSwipe; protected MMPossibleSwipeDirections _swipeDirection; protected float _lastPointerUpAt = 0f; protected float _swipeStartedAt = 0f; protected float _swipeEndedAt = 0f; /// /// Invokes a swipe event with the correct properties /// protected virtual void Swipe() { float duration = _swipeEndedAt - _swipeStartedAt; MMSwipeEvent swipeEvent = new MMSwipeEvent (_swipeDirection, _angle, _length, _firstTouchPosition, _destination, duration); MMEventManager.TriggerEvent(swipeEvent); if (ZoneSwiped != null) { ZoneSwiped.Invoke (swipeEvent); } } /// /// Raises the press event /// protected virtual void Press() { if (ZonePressed != null) { ZonePressed.Invoke (); } } /// /// Triggers the bound pointer down action /// public virtual void OnPointerDown(PointerEventData data) { #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER _firstTouchPosition = Mouse.current.position.ReadValue(); #else _firstTouchPosition = Input.mousePosition; #endif _swipeStartedAt = Time.unscaledTime; } /// /// Triggers the bound pointer up action /// public virtual void OnPointerUp(PointerEventData data) { if (Time.frameCount == _lastPointerUpAt) { return; } #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER _destination = Mouse.current.position.ReadValue(); #else _destination = Input.mousePosition; #endif _deltaSwipe = _destination - _firstTouchPosition; _length = _deltaSwipe.magnitude; // if the swipe has been long enough if (_length > MinimalSwipeLength) { _angle = MMMaths.AngleBetween (_deltaSwipe, Vector2.right); _swipeDirection = AngleToSwipeDirection (_angle); _swipeEndedAt = Time.unscaledTime; Swipe (); } // if it's just a press if (_deltaSwipe.magnitude < MaximumPressLength) { Press (); } _lastPointerUpAt = Time.frameCount; } /// /// Triggers the bound pointer enter action when touch enters zone /// public virtual void OnPointerEnter(PointerEventData data) { if (!MouseMode) { OnPointerDown (data); } } /// /// Triggers the bound pointer exit action when touch is out of zone /// public virtual void OnPointerExit(PointerEventData data) { if (!MouseMode) { OnPointerUp(data); } } /// /// Determines a MMPossibleSwipeDirection out of an angle in degrees. /// /// The to swipe direction. /// Angle in degrees. protected virtual MMPossibleSwipeDirections AngleToSwipeDirection(float angle) { if ((angle < 45) || (angle >= 315)) { return MMPossibleSwipeDirections.Right; } if ((angle >= 45) && (angle < 135)) { return MMPossibleSwipeDirections.Up; } if ((angle >= 135) && (angle < 225)) { return MMPossibleSwipeDirections.Left; } if ((angle >= 225) && (angle < 315)) { return MMPossibleSwipeDirections.Down; } return MMPossibleSwipeDirections.Right; } } }