- Home /
Pinching invokes SingleTouch
I am developing an Augmented Reality App with a rather simple user interaction. The user is able to pinch to scale some 3D model and make single touches to loop through a set of animations for every 3D model.
Both works fine, but the problem is, when I am pinching then sometimes also a single touch is invoked when I end the pinching. THis is due to the fact, that you are not really able to lift both your fingers at the exact same time. This leads to the situation that after the pinching there is a time where only one finger remains on the touchscreen which further invokes a single touch.
Of course i dont want the user to invoke an animation nearly everytime he just wants to scale to model with pinching. I don't know how to tackle this problem. See my Code here:
void Update ()
{
for (int i = 0; i < Input.touchCount; i++) {
if (Input.touchCount == 1 && Input.GetTouch (i).phase == TouchPhase.Ended) {
if (Input.GetTouch (i).position.x < Screen.width && Input.GetTouch (i).position.y < Screen.height) {
if (isLink) {
Application.OpenURL (link);
} else {
if (counter >= currentAnimations.Length) {
counter = 0;
}
currentObject.animation.Play (currentAnimations [counter]);
counter++;
}
}
}
}
}
void LateUpdate ()
{
DetectTouchMovement.Calculate ();
if (DetectTouchMovement.pinchDistanceDelta != 0) {
Debug.Log ("Transform " + currentObject.transform.localScale.x + "; initial " + trackables[trackablesCounter].getInitialScale().x + "; factored " + trackables[trackablesCounter].getInitialScale().x + factor * 15);
}
// if zooming out
if ((DetectTouchMovement.pinchDistanceDelta < 0 || Input.GetKey("q"))&& currentObject.transform.localScale.x > trackables[trackablesCounter].getInitialScale().x ) {
logCurrentObject ();
currentObject.transform.localScale = new Vector3 (currentObject.transform.localScale.x - factor, currentObject.transform.localScale.y - factor, currentObject.transform.localScale.z - factor);
Debug.Log ("SCALE--------------: " + currentObject.transform.localScale.x + " 2: " + trackables[trackablesCounter].getInitialScale().x + factor * 15);
}
// if zooming in
if ((DetectTouchMovement.pinchDistanceDelta > 0 || Input.GetKey("w"))&& currentObject.transform.localScale.x < trackables[trackablesCounter].getInitialScale().x + factor * 15) {
logCurrentObject ();
currentObject.transform.localScale = new Vector3 (currentObject.transform.localScale.x + factor, currentObject.transform.localScale.y + factor, currentObject.transform.localScale.z + factor);
Debug.Log ("SCALE--------------: " + currentObject.transform.localScale.x + " 2: " + trackables[trackablesCounter].getInitialScale().x + factor * 15);
}
}
And here the DetectTouchMovement which i got from somewhere on the Internet, i forgot from where to be honest:
const float pinchTurnRatio = Mathf.PI / 2;
const float minTurnAngle = 0;
const float pinchRatio = 1;
const float minPinchDistance = 0;
const float panRatio = 1;
const float minPanDistance = 0;
/// <summary>
/// The delta of the angle between two touch points
/// </summary>
static public float turnAngleDelta;
/// <summary>
/// The angle between two touch points
/// </summary>
static public float turnAngle;
/// <summary>
/// The delta of the distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistanceDelta;
/// <summary>
/// The distance between two touch points that were distancing from each other
/// </summary>
static public float pinchDistance;
/// <summary>
/// Calculates Pinch and Turn - This should be used inside LateUpdate
/// </summary>
static public void Calculate () {
pinchDistance = pinchDistanceDelta = 0;
turnAngle = turnAngleDelta = 0;
// if two fingers are touching the screen at the same time ...
if (Input.touchCount == 2) {
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
// ... if at least one of them moved ...
if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved) {
// ... check the delta distance between them ...
pinchDistance = Vector2.Distance(touch1.position, touch2.position);
float prevDistance = Vector2.Distance(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
pinchDistanceDelta = pinchDistance - prevDistance;
// ... if it's greater than a minimum threshold, it's a pinch!
if (Mathf.Abs(pinchDistanceDelta) > minPinchDistance) {
pinchDistanceDelta *= pinchRatio;
} else {
pinchDistance = pinchDistanceDelta = 0;
}
// ... or check the delta angle between them ...
turnAngle = Angle(touch1.position, touch2.position);
float prevTurn = Angle(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
turnAngleDelta = Mathf.DeltaAngle(prevTurn, turnAngle);
// ... if it's greater than a minimum threshold, it's a turn!
if (Mathf.Abs(turnAngleDelta) > minTurnAngle) {
turnAngleDelta *= pinchTurnRatio;
} else {
turnAngle = turnAngleDelta = 0;
}
}
}
}
Answer by Fattie · Aug 26, 2013 at 12:12 PM
Hi Granny,
first it's worth noting that generally touch interface code is by no means easy
(eg ! http://answers.unity3d.com/questions/292333/how-to-calculate-swipe-speed-on-ios.html that on merely the issue of measurement)
Fundamentally, you just need a "stateful solution".
So, the computer should "know" if you were "just now" doing a two-finger move.
So do this. Have a variable "IWasDoingATwoFingerMove" which is a boolean.
Then carefully follow these THREE RULES......
1) whenever you are doing a two-finger move. Set IWasDoingATwoFingerMove to TRUE.
2) critically, whenever you see ZERO fingers on the glass, set IWasDoingATwoFingerMove to FALSE.
(Note - this means that "every frame" when the machine is just sitting there, it will set it to false. NO problem at all with that.)
3) Finally. somewhere you have code that says something like this:
"if one finger ..
then ..
change my animation"
you must change it to this:
"if one finger ..
then ..
if ( IWasDoingATwoFingerMove is true)
{
simply do nothing, return
}
else ..
{
change my animation, proceed as before
}"
So that's how you do it. Hope it helps!
NB - I'm pretty sure your code is a bit messy; it may pay to start over from scratch. For example, it's very unlikely you need to use "LateUpdate" for any reason. That being said, if you can find "some, any" example code that does what you want -- fair enough. It's a pain in the ass programming this. So, just modify it exactly as I explain here and you'll solve the "phantom one finger" problem. Hope it helps!
Works perfectly. I feel ashamed that I didn't think of this myself.
"Be ashamed of nothing" - F. Neitzsche
State-ful program$$anonymous$$g is, I suppose, the most difficult program$$anonymous$$g as you have to think over time (I mean, backwards forwards and all over the place in time), rather than linearly. Nothing to feel ashamed there!