258 lines
8.1 KiB
C#
258 lines
8.1 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
|
|
[System.Flags]
|
|
public enum TKSwipeDirection
|
|
{
|
|
Left = ( 1 << 0 ),
|
|
Right = ( 1 << 1 ),
|
|
Up = ( 1 << 2 ),
|
|
Down = ( 1 << 3 ),
|
|
|
|
UpLeft = ( 1 << 4 ),
|
|
DownLeft = ( 1 << 5 ),
|
|
UpRight = ( 1 << 6 ),
|
|
DownRight = ( 1 << 7 ),
|
|
|
|
Horizontal = ( Left | Right ),
|
|
Vertical = ( Up | Down ),
|
|
Cardinal = ( Horizontal | Vertical ),
|
|
|
|
DiagonalUp = ( UpLeft | UpRight ),
|
|
DiagonalDown = ( DownLeft | DownRight ),
|
|
DiagonalLeft = ( UpLeft | DownLeft ),
|
|
DiagonalRight = ( UpRight | DownRight ),
|
|
Diagonal = ( DiagonalUp | DiagonalDown ),
|
|
|
|
RightSide = ( Right | DiagonalRight ),
|
|
LeftSide = ( Left | DiagonalLeft ),
|
|
TopSide = ( Up | DiagonalUp ),
|
|
BottomSide = ( Down | DiagonalDown ),
|
|
|
|
All = ( Horizontal | Vertical | Diagonal )
|
|
}
|
|
|
|
public class TKSwipeRecognizer : TKAbstractGestureRecognizer
|
|
{
|
|
/// <summary>
|
|
/// The event that fires when a swipe is recognized.
|
|
/// </summary>
|
|
public event System.Action<TKSwipeRecognizer> gestureRecognizedEvent;
|
|
|
|
/// <summary>
|
|
/// The maximum amount of time for the motion to be considered a swipe.
|
|
/// Setting to 0f will disable the time restriction completely.
|
|
/// </summary>
|
|
public float timeToSwipe = 0.5f;
|
|
|
|
/// <summary>
|
|
/// The velocity of the swipe, in centimeters based on the screen resolution
|
|
/// and pixel density, if available.
|
|
/// </summary>
|
|
public float swipeVelocity { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The direction that the swipe was made in. Possibilities include the four
|
|
/// cardinal directions and the four diagonal directions.
|
|
/// </summary>
|
|
public TKSwipeDirection completedSwipeDirection { get; private set; }
|
|
|
|
/// <summary>
|
|
/// The minimum number of simultaneous touches (fingers) on the screen to trigger
|
|
/// this swipe recognizer. Default is 1.
|
|
/// </summary>
|
|
public int minimumNumberOfTouches = 1;
|
|
|
|
/// <summary>
|
|
/// The maximum number of simultaneous touches (fingers) on the screen to trigger
|
|
/// this swipe recognizer. Default is 2.
|
|
/// </summary>
|
|
public int maximumNumberOfTouches = 2;
|
|
|
|
/// <summary>
|
|
/// If true, will trigger on the frame that the criteria for a swipe are first met.
|
|
/// If false, will only trigger on completion of the motion, when the touch is lifted.
|
|
/// </summary>
|
|
public bool triggerWhenCriteriaMet = true;
|
|
|
|
|
|
/// <summary>
|
|
/// The minimum distance in centimeters that the gesture has to make to be considered
|
|
/// a proper swipe, based on resolution and pixel density. Default is 2cm.
|
|
/// </summary>
|
|
private float _minimumDistance = 2f;
|
|
|
|
/// <summary>
|
|
/// The maximum distance in centimeters that the gesture has to make to be considered
|
|
/// a proper swipe.
|
|
/// </summary>
|
|
private float _maximumDistance = 10f;
|
|
|
|
/// <summary>
|
|
/// The individual points that make up the gesture, recorded every frame from when a
|
|
/// finger is first pressed to the screen until it's lifted. Only tracks the first touch
|
|
/// on the screen, in the case of multiple touches.
|
|
/// </summary>
|
|
private List<Vector2> _points = new List<Vector2>();
|
|
|
|
/// <summary>
|
|
/// The time that the gesture started. Is used to determine if the time limit has been
|
|
/// passed, and whether to ignore further checks.
|
|
/// </summary>
|
|
private float _startTime;
|
|
|
|
|
|
/// <summary>
|
|
/// The first touch point in the gesture.
|
|
/// </summary>
|
|
public Vector2 startPoint
|
|
{
|
|
get { return this._points.FirstOrDefault(); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// The last touch point in the gesture.
|
|
/// </summary>
|
|
public Vector2 endPoint
|
|
{
|
|
get { return this._points.LastOrDefault(); }
|
|
}
|
|
|
|
|
|
public TKSwipeRecognizer() : this( 2f, 10f )
|
|
{ }
|
|
|
|
public TKSwipeRecognizer( float minimumDistanceCm, float maximumDistanceCm )
|
|
{
|
|
this._minimumDistance = minimumDistanceCm;
|
|
this._maximumDistance = maximumDistanceCm;
|
|
}
|
|
|
|
|
|
private bool checkForSwipeCompletion( TKTouch touch )
|
|
{
|
|
// if we have a time stipulation and we exceeded it stop listening for swipes, fail
|
|
if( timeToSwipe > 0.0f && ( Time.time - this._startTime ) > timeToSwipe )
|
|
return false;
|
|
|
|
// if we don't have at least two points to test yet, then fail
|
|
if( this._points.Count < 2 )
|
|
return false;
|
|
|
|
// the ideal distance in pixels from the start to the finish
|
|
float idealDistance = Vector2.Distance( startPoint, endPoint );
|
|
|
|
// the ideal distance in centimeters, based on the screen pixel density
|
|
float idealDistanceCM = idealDistance / TouchKit.instance.ScreenPixelsPerCm;
|
|
|
|
// if the distance moved in cm was less than the minimum,
|
|
if( idealDistanceCM < this._minimumDistance || idealDistanceCM > this._maximumDistance )
|
|
return false;
|
|
|
|
// add up distances between all points sampled during the gesture to get the real distance
|
|
float realDistance = 0f;
|
|
for( int i = 1; i < this._points.Count; i++ )
|
|
realDistance += Vector2.Distance( this._points[i], this._points[i - 1] );
|
|
|
|
// if the real distance is 10% greater than the ideal distance, then fail
|
|
// this weeds out really irregular "lines" and curves from being considered swipes
|
|
if( realDistance > idealDistance * 1.1f )
|
|
return false;
|
|
|
|
// the speed in cm/s of the swipe
|
|
swipeVelocity = idealDistanceCM / ( Time.time - this._startTime );
|
|
|
|
// turn the slope of the ideal swipe line into an angle in degrees
|
|
Vector2 v2 = ( endPoint - startPoint ).normalized;
|
|
float swipeAngle = Mathf.Atan2( v2.y, v2.x ) * Mathf.Rad2Deg;
|
|
if( swipeAngle < 0 )
|
|
swipeAngle = 360 + swipeAngle;
|
|
swipeAngle = 360 - swipeAngle;
|
|
|
|
// depending on the angle of the line, give a logical swipe direction
|
|
if( swipeAngle >= 292.5f && swipeAngle <= 337.5f )
|
|
completedSwipeDirection = TKSwipeDirection.UpRight;
|
|
else if( swipeAngle >= 247.5f && swipeAngle <= 292.5f )
|
|
completedSwipeDirection = TKSwipeDirection.Up;
|
|
else if( swipeAngle >= 202.5f && swipeAngle <= 247.5f )
|
|
completedSwipeDirection = TKSwipeDirection.UpLeft;
|
|
else if( swipeAngle >= 157.5f && swipeAngle <= 202.5f )
|
|
completedSwipeDirection = TKSwipeDirection.Left;
|
|
else if( swipeAngle >= 112.5f && swipeAngle <= 157.5f )
|
|
completedSwipeDirection = TKSwipeDirection.DownLeft;
|
|
else if( swipeAngle >= 67.5f && swipeAngle <= 112.5f )
|
|
completedSwipeDirection = TKSwipeDirection.Down;
|
|
else if( swipeAngle >= 22.5f && swipeAngle <= 67.5f )
|
|
completedSwipeDirection = TKSwipeDirection.DownRight;
|
|
else // swipeAngle >= 337.5f || swipeAngle <= 22.5f
|
|
completedSwipeDirection = TKSwipeDirection.Right;
|
|
|
|
return true;
|
|
}
|
|
|
|
internal override void fireRecognizedEvent()
|
|
{
|
|
if( gestureRecognizedEvent != null )
|
|
gestureRecognizedEvent( this );
|
|
}
|
|
|
|
internal override bool touchesBegan( List<TKTouch> touches )
|
|
{
|
|
if( state == TKGestureRecognizerState.Possible )
|
|
{
|
|
// add any touches on screen
|
|
for( int i = 0; i < touches.Count; i++ )
|
|
this._trackingTouches.Add( touches[i] );
|
|
|
|
// if the number of touches is within our constraints, begin tracking
|
|
if( this._trackingTouches.Count >= minimumNumberOfTouches && this._trackingTouches.Count <= maximumNumberOfTouches )
|
|
{
|
|
// reset everything
|
|
this._points.Clear();
|
|
this._points.Add( touches[0].position );
|
|
|
|
this._startTime = Time.time;
|
|
state = TKGestureRecognizerState.Began;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
internal override void touchesMoved( List<TKTouch> touches )
|
|
{
|
|
// only bother doing anything if we haven't recognized or failed yet
|
|
if( state == TKGestureRecognizerState.Began )
|
|
{
|
|
this._points.Add( touches[0].position );
|
|
|
|
// if we're triggering when the criteria is met, then check for completion every frame
|
|
if( triggerWhenCriteriaMet && checkForSwipeCompletion( touches[0] ) )
|
|
state = TKGestureRecognizerState.Recognized;
|
|
}
|
|
}
|
|
|
|
internal override void touchesEnded( List<TKTouch> touches )
|
|
{
|
|
// if we haven't recognized or failed yet
|
|
if( state == TKGestureRecognizerState.Began )
|
|
{
|
|
this._points.Add( touches[0].position );
|
|
|
|
// last frame, one last check- recognized or fail
|
|
if( checkForSwipeCompletion( touches[0] ) )
|
|
state = TKGestureRecognizerState.Recognized;
|
|
else
|
|
state = TKGestureRecognizerState.FailedOrEnded;
|
|
}
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return string.Format( "{0}, swipe direction: {1}, swipe velocity: {2}, start point: {3}, end point: {4}",
|
|
base.ToString(), completedSwipeDirection, swipeVelocity, startPoint, endPoint );
|
|
}
|
|
}
|