using UnityEngine; using System.Collections; /// /// Detect multiple consecutive tap gestures at the same location /// [AddComponentMenu( "FingerGestures/Gesture Recognizers/Tap (Multi)" )] public class MultiTapGestureRecognizer : AveragedGestureRecognizer { /// /// Event fired when a tap occurs (if RequiredTaps is 0) or when the exact number of RequiredTaps has been reached /// public event EventDelegate OnTap; /// /// Exact number of taps required to succesfully recognize the tap gesture. /// If RequiredTaps is set to a positive value, the gesture recognizer will reset once the number of consecutive taps performed is equal to /// this value. /// /// public int RequiredTaps = 0; /// /// When set to true, the OnTap event will fire each time a tap occurs. /// When set to false, the OnTap event will only be fired on the last tap produced (either by time-out or when reaching the RequiredTaps count) /// /// public bool RaiseEventOnEachTap = false; /// /// The maximum amount of the time that can elapse between two consecutive taps without causing the recognizer to reset. /// Set to 0 to ignore this setting. /// public float MaxDelayBetweenTaps = 0.25f; /// /// The maximum total duration of a tap sequence, in seconds. The tap recognizer automatically resets after this duration. /// Set to 0 to ignore this setting. /// public float MaxDuration = 0.0f; /// /// How far the finger can move from its initial position without making the gesture fail /// public float MoveTolerance = 5.0f; int taps = 0; bool down = false; bool wasDown = false; float lastDownTime = 0; float lastTapTime = 0; /// /// Get the current number of consecutive taps achieved /// public int Taps { get { return taps; } } bool HasTimedOut() { // check elapsed time since last tap if( MaxDelayBetweenTaps > 0 && ( Time.time - lastTapTime > MaxDelayBetweenTaps ) ) return true; // check elapsed time since beginning of gesture if( MaxDuration > 0 && ( ElapsedTime > MaxDuration ) ) return true; return false; } protected override void Reset() { taps = 0; down = false; wasDown = false; base.Reset(); } protected override void OnBegin( FingerGestures.IFingerList touches ) { Position = touches.GetAveragePosition(); StartPosition = Position; lastTapTime = Time.time; //UnityEngine.Debug.Log( this + " OnBegin @ " + StartPosition ); } protected override GestureState OnActive( FingerGestures.IFingerList touches ) { wasDown = down; down = false; if( touches.Count == RequiredFingerCount ) { down = true; lastDownTime = Time.time; } else if( touches.Count == 0 ) { down = false; } else { // some fingers were lifted off if( touches.Count < RequiredFingerCount ) { // give a bit of buffer time to lift-off the remaining fingers if( Time.time - lastDownTime > 0.25f ) return GestureState.Failed; } else // fingers were added { if( !Young( touches ) ) return GestureState.Failed; } } if( HasTimedOut() ) { // if we requested unlimited taps and landed at least one, consider this a success if( RequiredTaps == 0 && Taps > 0 ) { // if we didn't raise a tap event on each tap, at least raise the event once at the end of the tap sequence if( !RaiseEventOnEachTap ) RaiseOnTap(); return GestureState.Recognized; } // else, timed out return GestureState.Failed; } if( down ) { // check if finger moved too far from start position float sqrDist = Vector3.SqrMagnitude( touches.GetAveragePosition() - StartPosition ); if( sqrDist >= MoveTolerance * MoveTolerance ) return GestureState.Failed; } if( wasDown != down ) { // fingers were just released if( !down ) { ++taps; lastTapTime = Time.time; // If the requested tap count has been reached, validate the gesture and stop if( RequiredTaps > 0 && taps >= RequiredTaps ) { RaiseOnTap(); return GestureState.Recognized; } if( RaiseEventOnEachTap ) RaiseOnTap(); } } return GestureState.InProgress; } protected void RaiseOnTap() { if( OnTap != null ) OnTap( this ); } }