- Home /
C# script for unity camera. Detect difference between two finger swipe and pinch to zoom?
I have a problem with my current code, it works to detect the zoom, and i think my code detects the difference between rotation and pinch, but if i put two fingers down and swipe it still zooms. How do i detect this and stop it? I also have to accomodate for users being sloppy when pinching and zoom and move fingers sideways a little bit (probably defining a variable that can be changed)
Here is my current code:
using UnityEngine;
using System.Collections;
public class CameraZoomPinch : MonoBehaviour
{
public int speed = 4;
public Camera selectedCamera;
public float MINSCALE = 2.0F;
public float MAXSCALE = 5.0F;
public float minPinchSpeed = 5.0F;
public float varianceInDistances = 5.0F;
private float touchDelta = 0.0F;
private Vector2 prevDist = new Vector2(0,0);
private Vector2 curDist = new Vector2(0,0);
private float speedTouch0 = 0.0F;
private float speedTouch1 = 0.0F;
private float startAngleBetweenTouches = 0.0F;
private int vertOrHorzOrientation = 0; //this tells if the two fingers to each other are oriented horizontally or vertically, 1 for vertical and -1 for horizontal
private Vector2 midPoint = new Vector2(0,0); //store and use midpoint to check if fingers exceed a limit defined by midpoint for oriantation of fingers
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.touchCount == 2 && Input.GetTouch(0).phase == TouchPhase.Began && Input.GetTouch(1).phase == TouchPhase.Began)
{
startAngleBetweenTouches = Vector2.Angle(Input.GetTouch(0).position, Input.GetTouch(1).position); //to determine that gesture isnt a rotation
midPoint = new Vector2((Input.GetTouch(0).position.x - Input.GetTouch(1).position.x), (Input.GetTouch(0).position.y - Input.GetTouch(1).position.y)); //store midpoint from first touches
if ((Input.GetTouch(0).position.x - Input.GetTouch(1).position.x) > (Input.GetTouch(0).position.y - Input.GetTouch(1).position.y))
{
vertOrHorzOrientation = -1;
}
if ((Input.GetTouch(0).position.x - Input.GetTouch(1).position.x) < (Input.GetTouch(0).position.y - Input.GetTouch(1).position.y))
{
vertOrHorzOrientation = 1;
}
}
if (Input.touchCount == 2 && Input.GetTouch(0).phase == TouchPhase.Moved && Input.GetTouch(1).phase == TouchPhase.Moved)
{
curDist = Input.GetTouch(0).position - Input.GetTouch(1).position; //current distance between finger touches
prevDist = ((Input.GetTouch(0).position - Input.GetTouch(0).deltaPosition) - (Input.GetTouch(1).position - Input.GetTouch(1).deltaPosition)); //difference in previous locations using delta positions
touchDelta = curDist.magnitude - prevDist.magnitude;
speedTouch0 = Input.GetTouch(0).deltaPosition.magnitude / Time.deltaTime;
speedTouch1 = Input.GetTouch(1).deltaPosition.magnitude / Time.deltaTime;
//(curDist < prevDist --- inward pinch) && (if touch0 is fast enough) && (if touch1 is fast enough) && (angle of two touches-using vector2.angle-is less than an angle limit to make sure pinch isnt a rotation)
if ((touchDelta < 1) && (speedTouch0 > minPinchSpeed) && (speedTouch1 > minPinchSpeed) && (Vector2.Angle(Input.GetTouch(0).position, Input.GetTouch(1).position) < (startAngleBetweenTouches+10)) && (Vector2.Angle(Input.GetTouch(0).position, Input.GetTouch(1).position) > (startAngleBetweenTouches-10))) //
{
//(if the two touches are oriented vertically) && (if touch0 x is less than right side of midpoint x) or (if touch0 x is greater than left of midpoint x) && (if touch1 x is less than right side of midpoint x) or (if touch1 x is greater than left of midpoint x) (all values are assuming left and right variances of 20 pixels)
if ((vertOrHorzOrientation == 1) && ((Input.GetTouch(0).position.x < midPoint.x + 20) || (Input.GetTouch(0).position.x > midPoint.x -20)) && ((Input.GetTouch(1).position.x < midPoint.x + 20) || (Input.GetTouch(1).position.x > midPoint.x -20)))
{
selectedCamera.fieldOfView = Mathf.Clamp(selectedCamera.fieldOfView + (1 * speed),15,90);
}
//(same as above, but these checks are for horizontal orientation of touches and the y components are checked for limiting the direction)
if ((vertOrHorzOrientation == -1) && ((Input.GetTouch(0).position.y < midPoint.y + 20) || (Input.GetTouch(0).position.y > midPoint.y -20)) && ((Input.GetTouch(1).position.y < midPoint.y + 20) || (Input.GetTouch(1).position.y > midPoint.y -20)))
{
selectedCamera.fieldOfView = Mathf.Clamp(selectedCamera.fieldOfView + (1 * speed),15,90);
}
}
if ((touchDelta > 1) && (speedTouch0 > minPinchSpeed) && (speedTouch1 > minPinchSpeed) && (Vector2.Angle(Input.GetTouch(0).position, Input.GetTouch(1).position) < (startAngleBetweenTouches+10)) && (Vector2.Angle(Input.GetTouch(0).position, Input.GetTouch(1).position) > (startAngleBetweenTouches-10)))
{
if ((vertOrHorzOrientation == 1) && ((Input.GetTouch(0).position.x < midPoint.x + 20) || (Input.GetTouch(0).position.x > midPoint.x -20)) && ((Input.GetTouch(1).position.x < midPoint.x + 20) || (Input.GetTouch(1).position.x > midPoint.x -20)))
{
selectedCamera.fieldOfView = Mathf.Clamp(selectedCamera.fieldOfView - (1 * speed),15,90);
}
if ((vertOrHorzOrientation == -1) && ((Input.GetTouch(0).position.y < midPoint.y + 20) || (Input.GetTouch(0).position.y > midPoint.y -20)) && ((Input.GetTouch(1).position.y < midPoint.y + 20) || (Input.GetTouch(1).position.y > midPoint.y -20)))
{
selectedCamera.fieldOfView = Mathf.Clamp(selectedCamera.fieldOfView - (1 * speed),15,90);
}
}
}
}
}
How do i edit this to detect if a user swipe with two fingers and pinches to zoom? (i also have to take into account a user can have the pinch horizontal, vertical, or a combo of the two diagonally which i tried doing with the midpoint code.
Does somebody know this answer? This is covered all the time by people's projects, but why doesn't NOBODY want to give insight into how THEY did it? I have spent over 2 weeks on this code and concept....
Dude, chill. Try reducing your question. Picture yourself trying to answer a question this big. Go to http://stackexchange.com/sites pick your favorite topic, one you're an expert on, and try to answer the biggest questions there. At least 100 lines like yours, with something dense to read. Code reviews are always a pain to do, specially when the code is this big and unfiltered.
ok ill structure my questions better and break them down. Im just getting used to this being viewed and posting using my galaxy tab10. 1. The main question is defined in the title tho. I just need a way to discern pinching from two finger swiping, as my code zooms if i swipe (obviously im not pinching to zoom and other apps supports those gestures).
Actually, your other question on the same topic is much better already: http://answers.unity3d.com/questions/182757/two-finger-swipe-vs-pinch-and-zoom-problem.html which is indeed much more a question about logic than Unity3D or C#.
Answer by WillTAtl · Nov 20, 2011 at 02:22 AM
first, whining never helps, it won't get you pity or sympathy. You're asking for help from people who have no reason to help you and do not stand to benefit in any way from doing so; you're entitled to nothing. Remember that.
That said, I'll attempt to help anyway this time, despite your attitude, because I do understand your frustration.
This is basically a variation of the standard mouse dragging vs clicking problem, and the same solution ought to work. What you need is some state information.
in Idle state:
check for a two-finger touch. If you get one, remember the finger positions and calculate and store the distance between them, and change state to TwoFingerTouch.
in TwoFingerTouch state:
If one or both touches have ended: compare their final positions to their originals. If they've both moved in the same general direction, and moved far enough to qualify as a swipe, ... do a swipe, and go back to the Idle state. If they moved different directions, or not far enough, go back to Idle state.
If both touches are still there, calc the current distance between them. If it's reduced enough, transition to PinchZoom state.
in PinchZoom state:
Calculate the new distance between the fingers, and apply zoom level based on this relative to original distance between them.
If one or both fingers released, return to Idle state.
state machine
As for how to implement this simple state machine, there are many ways, a search for State Machines will probably find you many examples. Here's one very simple way it could be done:
enum TouchState {
Idle,
TwoFingerTouch,
PinchZoom,
};
var currentState:TouchState=Idle;
function Update()
{
/*any pre-processing of input common to all states here */
switch(idle)
{
case TouchState.Idle:
/*Idle state code here*/
break;
case TouchState.TwoFingerTouch:
/*Two finger touch state code here*/
break;
case TouchState.PinchZoom:
/*PinchZoom state here*/
break;
}
}
Btw the first statement makes all forum posters seem selfish and makes this system seem very one way, where ppl expect help but never give it. Sorry about "whining" but this question was up long enough for people to see and yet they chose not to respond to such an easy question, which kinda concerns me. And i wasnt lookkng for sympathy. Its a forum. Asking questions why others dont post is acceptabke (obviously to a point).
Second, i would prefer using code i have. If i wanted to use state machines i would have posted elsewhere and wouldnt have posted code. I also would have used playmaker rather than code the fsm in a script. How can i modify my code to not zoom while swiping with both fingers.
very simple reason people were ignoring the question. Try typing "pinch zoom," "swipe," or "flick" into the search box at the top, you get pages and pages of people asking this same question.
If the only acceptable answer is one that specifically involves someone fixing your specific code, then you're in the wrong place anyway. FAQ rules clearly state, answer must be reasonably interesting or useful to at least one person besides you; if the only answer you want is how to fix your specific code, your question doesn't meet that criteria.
And also, to add thanks for helping. I just am curious how to do this with code i have rather than resort to FS$$anonymous$$ for everything, i have this coded this way otherwise it wont fit my OOD i wish to have.
$$anonymous$$ost people who i have searched use a similar code, so i assumed people would be able to help with the code that seems pretty common. Obiously it is interesting to others besides just me, or people wouldn't be posting the question using code similar to $$anonymous$$e (and not using FS$$anonymous$$'s)
you don't need to rewrite the code to use enums or switches; you just need to add a $$anonymous$$imal amount of state info.
Basically, what you're doing now is using a series of If(condition..) statements, where the condition tries to identify which state you're in for you. The problem with this is that it can and will detect pinch and flick in the same updates.
All you have to do is add a new variable, isPinching. When pinch is first detected, set isPinch to true, and when a pinch ends (one or both fingers releases), set it back to false. Then add !isPinch to the condition for swipe, so it will not swipe if it's detected a pinch. It's really not that different from what you're doing, but you absolutely are going to require at least this $$anonymous$$imal amount of state information.
And I must say, despite what you think, using states will actually make it far easier to extend the code if you wanted to add more input types later, like three-finger swipes or two- or three-finger taps. The problem you're having is trying to explicitly and absolutely differentiate one from the other without any kind of state information. As illustrated by the other answer, this problem doesn't exist at all if you're only doing pinch, and it will get exponentially worse the more the more cases you add.
Answer by cregox · Nov 21, 2011 at 07:49 PM
Since I'm not sure what your question is, I'll go with the title and give you my C# script that will detect pinch. This is extracted from a 342 lines of code bloated script, so I'm sorry if I'm missing something. Just let me know and I'll dig deeper to fix it:
using UnityEngine;
using System.Collections;
public class DetectPinch : MonoBehaviour {
const float pinchRatio = 0.005f; // this is from trial and error
const float minPinchDistance = 0;
///<summary>
/// Only update after all character movement logic has been handled.
///</summary>
void LateUpdate()
{
float pinchAmmount = 0f;
// if two fingers are touching the screen at the same time and ...
if (Input.touchCount == 2)
{
Touch touch1 = Input.touches[0];
Touch touch2 = Input.touches[1];
if (touch1.phase == TouchPhase.Moved || touch2.phase == TouchPhase.Moved)
{
// ... pinching, prepare ZOOM
float pinchDistance = Vector2.Distance(touch1.position, touch2.position);
float prevDistance = Vector2.Distance(touch1.position - touch1.deltaPosition,
touch2.position - touch2.deltaPosition);
float pinchDistanceDelta = pinchDistance - prevDistance;
if (Mathf.Abs(pinchDistanceDelta) > minPinchDistance)
{
pinchAmmount = pinchDistanceDelta * pinchRatio;
}
}
}
transform.position += Vector3.forward * pinchAmmount; // not so sure this will work
}
}
Hope this is enough to help you!
This code just handles punching to zoom, but dies not take into account if i swipe with two fingers, same as my code. I do like that you calculated the distance between fingers and set the position of camera closer or further depending on that. $$anonymous$$y camera uses fov, because i am planning on having it rotate and want to avoid complex circle math, so i used fov of the camera and used mathf. Clamp to limit its value to a certain degree value. (fov is field of view, a property of camera object that uses degrees)
Yes, I did consider what you said about swiping. But if this is not enough that means I don't understand what you meant. In this code, if you put two fingers down and swipe, it won't do anything, as long as you swipe it in equal distance. And you can increase "$$anonymous$$PinchDistance" to reduce sensibility of detecting the pinch. In other words, a higher value will require a higher distance between fingers to trigger the pinch. Here, if you can try it on android see if this is what you want: http://www.p3d.com.br/android
Your answer
Follow this Question
Related Questions
two finger swipe vs pinch and zoom problem 5 Answers
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Multitouch physics drag with TargetJoint2D 0 Answers
Android: After the third touch all touches get cancelled 1 Answer