Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TK Analog Recognizer 😎 #64

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 188 additions & 0 deletions Assets/TouchKit/Recognizers/TKAnalogRecognizer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
using UnityEngine;
using System;
using System.Collections.Generic;


/// <summary>
/// TouchKit Analog Recognizer to allow for an invisible analog which is
/// usually best when working with mobile devices to avoid having a cluncky UI
/// in the way of what's important to the player
/// </summary>
public class TKAnalogRecognizer : TKAbstractGestureRecognizer
{
public event Action<TKAnalogRecognizer> gestureRecognizedEvent;
public event Action<TKAnalogRecognizer> gestureCompleteEvent;

public AnimationCurve inputCurve = AnimationCurve.Linear(0.0f, 0.0f, 1.0f, 1.0f);
public Vector2 value;
public Vector2 touchPadCenter;

/// <summary>
/// How far out to extend from the center of the rect or the initial tap position
/// </summary>
public float touchPadRadius = 50f;

/// <summary>
/// If false, the center of the analog will be wherever the initial touch is inside the rect
/// </summary>
public bool useRectOrigin = false;

/// <summary>
/// if false, the radius will determine how far out from the center to go to get to 1 or -1
/// </summary>
public bool useRectSize = false;

/// <summary>
/// only necessary if there is a rect in the same space waiting for a tap gesture
/// </summary>
public bool ignoreInitialTouch = false;


/// <summary>
/// the constructor ensures we have a frame to work with for this recognizer
/// by default: use initial tap as analog center and default radius
/// </summary>
public TKAnalogRecognizer(TKRect frame)
{
this.boundaryFrame = frame;
this.ignoreInitialTouch = false;
this.useRectOrigin = false;
this.useRectSize = false;
}

/// <summary>
/// ignoring the initial touch is only necessary if there is a rect in the same space waiting for a tap gesture
/// </summary>
public TKAnalogRecognizer(TKRect frame, bool ignoreInitialTouch)
{
this.boundaryFrame = frame;
this.ignoreInitialTouch = ignoreInitialTouch;
this.useRectOrigin = false;
this.useRectSize = false;
}

/// <summary>
/// change radius size
/// </summary>
public TKAnalogRecognizer(TKRect frame, float radius)
{
this.boundaryFrame = frame;
this.touchPadRadius = radius;
this.ignoreInitialTouch = false;
this.useRectOrigin = false;
this.useRectSize = false;
}

/// <summary>
/// set the analog radius and use the rect's origin as the center point
/// </summary>
public TKAnalogRecognizer(TKRect frame, float radius, bool useRectOrigin)
{
this.boundaryFrame = frame;
this.touchPadRadius = radius;
this.useRectOrigin = useRectOrigin;
this.ignoreInitialTouch = false;
this.useRectSize = false;
}

/// <summary>
/// use rect origin as center point and rect size to determine analog position
/// </summary>
public TKAnalogRecognizer(TKRect frame, bool useRectOrigin, bool useRectSize)
{
this.boundaryFrame = frame;
this.useRectOrigin = useRectOrigin;
this.useRectSize = useRectSize;
this.ignoreInitialTouch = false;
}

internal override bool touchesBegan(List<TKTouch> touches)
{
if (state == TKGestureRecognizerState.Possible)
{
for (var i = 0; i < touches.Count; i++)
{
// only add touches in the Began phase
if (touches[i].phase == TouchPhase.Began)
_trackingTouches.Add(touches[i]);
}

if (_trackingTouches.Count > 0)
{
state = TKGestureRecognizerState.Began;

// call through to touchesMoved so we set the value and set the state to RecognizedAndStillRecognizing which triggers the recognized event
touchesMoved(touches, ignoreInitialTouch);
}
}
return false;
}

internal override void touchesMoved(List<TKTouch> touches)
{

if (state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began)
{
var currentLocation = touchLocation();
value = currentLocation - (useRectOrigin ? boundaryFrame.Value.center : touchPadCenter);

// normalize from 0 - 1 and clamp
value.x = Mathf.Clamp(value.x / (useRectSize ? (boundaryFrame.Value.width * 0.5f) : touchPadRadius), -1f, 1f);
value.y = Mathf.Clamp(value.y / (useRectSize ? (boundaryFrame.Value.height * 0.5f) : touchPadRadius), -1f, 1f);

// apply our inputCurve
value.x = inputCurve.Evaluate(Mathf.Abs(value.x)) * Mathf.Sign(value.x);
value.y = inputCurve.Evaluate(Mathf.Abs(value.y)) * Mathf.Sign(value.y);

state = TKGestureRecognizerState.RecognizedAndStillRecognizing;
}
}

/// <summary>
/// If also has a tap recognizer we want to ignore the first touch as to not be confused in using the analog
/// </summary>
internal void touchesMoved(List<TKTouch> touches, bool ignoreInitialTouch)
{
if (state == TKGestureRecognizerState.Began && ignoreInitialTouch)
{
//cashe starting touch position and ignore initial touch in case it's a tap
touchPadCenter = startTouchLocation();
}
else
{
// call through to touchesMoved so we set the value and set the state to RecognizedAndStillRecognizing which triggers the recognized event
touchesMoved(touches);
}
}

internal override void touchesEnded(List<TKTouch> touches)
{
// remove any completed touches
for (var i = 0; i < touches.Count; i++)
{
if (touches[i].phase == TouchPhase.Ended)
_trackingTouches.Remove(touches[i]);
}

// if we had previously been recognizing fire our complete event
if (state == TKGestureRecognizerState.RecognizedAndStillRecognizing)
{
if (gestureCompleteEvent != null)
gestureCompleteEvent(this);
}

value = Vector2.zero;
state = TKGestureRecognizerState.FailedOrEnded;
}

internal override void fireRecognizedEvent()
{
if (gestureRecognizedEvent != null)
gestureRecognizedEvent(this);
}

public override string ToString()
{
return string.Format("[{0}] state: {1}, value: {2}", this.GetType(), state, value);
}
}
12 changes: 12 additions & 0 deletions Assets/TouchKit/Recognizers/TKAnalogRecognizer.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 60 additions & 1 deletion Assets/TouchKitDemos/DemoOne/DemoOne.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,67 @@ void OnGUI()
TouchKit.addGestureRecognizer( recognizer );
}

if(GUILayout.Button("Add Analog Recognizer"))
{
var recognizer = new TKAnalogRecognizer(new TKRect(0f, 0f, 125f, 125f));
recognizer.inputCurve = touchPadInputCurve;

if( GUILayout.Button( "Add Horizontal Swipe Recognizer" ) )
//change the default analog radius
recognizer.touchPadRadius = 100f;

recognizer.gestureRecognizedEvent += (r) =>
{
Debug.Log("analog recognizer fired: " + r);
};

// continuous gestures have a complete event so that we know when they are done recognizing
recognizer.gestureCompleteEvent += r =>
{
Debug.Log("analog gesture complete");
};

TouchKit.addGestureRecognizer(recognizer);
}

if (GUILayout.Button("Add Analog and Tap Recognizer"))
{
var analog = new TKAnalogRecognizer(new TKRect(0f, 0f, 125f, 125f), true);
analog.inputCurve = touchPadInputCurve;

//change the default analog radius
analog.touchPadRadius = 100f;

analog.gestureRecognizedEvent += (r) =>
{
Debug.Log("analog recognizer fired: " + r);
};

// continuous gestures have a complete event so that we know when they are done recognizing
analog.gestureCompleteEvent += r =>
{
Debug.Log("analog gesture complete");
};

TouchKit.addGestureRecognizer(analog);

var tap = new TKTapRecognizer();

// setting the rect to the same as the analog
tap.boundaryFrame = new TKRect(0, 0, 125f, 125f);

// we can also set the number of touches required for the gesture
if (Application.platform == RuntimePlatform.IPhonePlayer)
tap.numberOfTouchesRequired = 2;

tap.gestureRecognizedEvent += (r) =>
{
Debug.Log("tap recognizer fired: " + r);
};
TouchKit.addGestureRecognizer(tap);
}


if ( GUILayout.Button( "Add Horizontal Swipe Recognizer" ) )
{
var recognizer = new TKSwipeRecognizer();
recognizer.gestureRecognizedEvent += ( r ) =>
Expand Down
2 changes: 1 addition & 1 deletion ProjectSettings/ProjectVersion.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
m_EditorVersion: 5.5.0f3
m_EditorVersion: 2017.1.1f1
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ TouchKit comes with a few built in recognizers to get you started and to serve a
* **Button Recognizer**: generic button recognizer designed to work with any 2D sprite system at all
* **Pan Recognizer**: detects a pan gesture (one or more fingers down and moving around the screen)
* **TouchPad Recognizer**: detects and tracks a touch in an area and maps the location from -1 to 1 on the x and y axis based on the touches distance from the center of the area
* **Analog Recognizer**: detects and tracks a touch in an area and maps the location from -1 to 1 on the x and y axis based on the analog's radius and distance from the initial tap position
* **Swipe Recognizer**: detects swipes in the four cardinal directions
* **Pinch Recognizer**: detects pinches and reports back the delta scale
* **Rotation Recognizer**: detects two finger rotation and reports back the delta rotation
Expand Down
Loading