using UnityEngine; using UnityEngine.Events; using System.Collections.Generic; using Lean.Common; using FSA = UnityEngine.Serialization.FormerlySerializedAsAttribute; namespace Lean.Touch { /// This component allows you to detect when a specific amount of fingers begin touching the screen. [HelpURL(LeanTouch.PlusHelpUrlPrefix + "LeanMultiDown")] [AddComponentMenu(LeanTouch.ComponentPathPrefix + "Multi Down")] public class LeanMultiDown : MonoBehaviour { [System.Serializable] public class LeanFingerListEvent : UnityEvent> {} [System.Serializable] public class Vector3Event : UnityEvent {} [System.Serializable] public class Vector2Event : UnityEvent {} /// Ignore fingers with StartedOverGui? public bool IgnoreStartedOverGui { set { ignoreStartedOverGui = value; } get { return ignoreStartedOverGui; } } [FSA("IgnoreStartedOverGui")] [SerializeField] private bool ignoreStartedOverGui = true; /// If the specified object is set and isn't selected, then this component will do nothing. public LeanSelectable RequiredSelectable { set { requiredSelectable = value; } get { return requiredSelectable; } } [FSA("RequiredSelectable")] [SerializeField] private LeanSelectable requiredSelectable; /// The amount of fingers we are interested in. public int RequiredCount { set { requiredCount = value; } get { return requiredCount; } } [FSA("RequiredCount")] [SerializeField] private int requiredCount = 2; /// This event will be called if the above conditions are met when you first touch the screen. public LeanFingerListEvent OnFingers { get { if (onFingers == null) onFingers = new LeanFingerListEvent(); return onFingers; } } [SerializeField] private LeanFingerListEvent onFingers; /// The method used to find world coordinates from a finger. See LeanScreenDepth documentation for more information. public LeanScreenDepth ScreenDepth = new LeanScreenDepth(LeanScreenDepth.ConversionType.DepthIntercept); /// This event will be called if the above conditions are met when you first touch the screen. /// Vector3 = Finger position in world space. public Vector3Event OnWorld { get { if (onWorld == null) onWorld = new Vector3Event(); return onWorld; } } [SerializeField] private Vector3Event onWorld; /// This event will be called if the above conditions are met when you first touch the screen. /// Vector2 = Finger position in screen space. public Vector2Event OnScreen { get { if (onScreen == null) onScreen = new Vector2Event(); return onScreen; } } [SerializeField] private Vector2Event onScreen; [System.NonSerialized] private List fingers = new List(); #if UNITY_EDITOR protected virtual void Reset() { requiredSelectable = GetComponentInParent(); } #endif protected virtual void Awake() { if (requiredSelectable == null) { requiredSelectable = GetComponentInParent(); } } protected virtual void OnEnable() { LeanTouch.OnFingerDown += HandleFingerDown; LeanTouch.OnFingerUp += HandleFingerUp; } protected virtual void OnDisable() { LeanTouch.OnFingerDown -= HandleFingerDown; LeanTouch.OnFingerUp -= HandleFingerUp; } private void HandleFingerDown(LeanFinger finger) { if (ignoreStartedOverGui == true && finger.IsOverGui == true) { return; } if (requiredSelectable != null && requiredSelectable.IsSelected == false) { return; } fingers.Add(finger); if (fingers.Count == requiredCount) { if (onFingers != null) { onFingers.Invoke(fingers); } var screenPosition = LeanGesture.GetScreenCenter(fingers); if (onWorld != null) { var worldPosition = ScreenDepth.Convert(screenPosition, gameObject); onWorld.Invoke(worldPosition); } if (onScreen != null) { onScreen.Invoke(screenPosition); } } } private void HandleFingerUp(LeanFinger finger) { fingers.Remove(finger); } } } #if UNITY_EDITOR namespace Lean.Touch.Editor { using TARGET = LeanMultiDown; [UnityEditor.CanEditMultipleObjects] [UnityEditor.CustomEditor(typeof(TARGET))] public class LeanMultiDown_Editor : LeanEditor { private bool showUnusedEvents; protected override void OnInspector() { TARGET tgt; TARGET[] tgts; GetTargets(out tgt, out tgts); Draw("ignoreStartedOverGui", "Ignore fingers with StartedOverGui?"); Draw("requiredSelectable", "If the specified object is set and isn't selected, then this component will do nothing."); Draw("requiredCount", "The amount of fingers we are interested in."); Separator(); var usedA = Any(tgts, t => t.OnFingers.GetPersistentEventCount() > 0); var usedB = Any(tgts, t => t.OnWorld.GetPersistentEventCount() > 0); var usedC = Any(tgts, t => t.OnScreen.GetPersistentEventCount() > 0); var showUnusedEvents = DrawFoldout("Show Unused Events", "Show all events?"); if (usedA == true || showUnusedEvents == true) { Draw("onFingers"); } if (usedB == true || showUnusedEvents == true) { Draw("ScreenDepth"); Draw("onWorld"); } if (usedC == true || showUnusedEvents == true) { Draw("onScreen"); } } } } #endif