x


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.

more ▼

asked Nov 05, 2011 at 09:11 PM

1337GameDev gravatar image

1337GameDev
780 168 136 151

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....

Nov 20, 2011 at 01:54 AM 1337GameDev

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.

Nov 21, 2011 at 07:15 PM Cawas

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#.

Nov 22, 2011 at 12:44 PM Cawas

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).

Nov 21, 2011 at 10:20 PM 1337GameDev
(comments are locked)
10|3000 characters needed characters left

2 answers: sort voted first

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;
     }
 }
more ▼

answered Nov 20, 2011 at 02:22 AM

WillTAtl gravatar image

WillTAtl
822 7 9 18

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.

Nov 21, 2011 at 05:53 PM 1337GameDev

And also, to add thanks for helping. I just am curious how to do this with code i have rather than resort to FSM for everything, i have this coded this way otherwise it wont fit my OOD i wish to have.

Nov 21, 2011 at 05:59 PM 1337GameDev

Most 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 mine (and not using FSM's)

Nov 21, 2011 at 06:01 PM 1337GameDev

yes, it is very common not to know how to do this kind of input handling; aA lot of people don't understand that some sort of state information is in fact required. Basic mouse input is only slightly easier, and most people just rely on pre-implemented systems that send them BeginDrag/EndDrag/Click/Doubleclick events pre-processed - buy underlying systems based on input state.

A full state machine approach is not required, but without at least adding some state info in there, it's always going to keep getting confused when a pinch-like gesture becomes swipe-like, or vice-versa.

Nov 21, 2011 at 07:01 PM WillTAtl

So @Lord, did you find a working code or didn't you? 'Cuz now I don't know if you need a code review or a working code. Finally, what's FSM?

Nov 21, 2011 at 07:19 PM Cawas
(comments are locked)
10|3000 characters needed characters left

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!

more ▼

answered Nov 21, 2011 at 07:49 PM

Cawas gravatar image

Cawas
2.3k 116 110 127

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. My 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)

Nov 21, 2011 at 10:16 PM 1337GameDev

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 "minPinchDistance" 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

Nov 22, 2011 at 12:27 PM Cawas
(comments are locked)
10|3000 characters needed characters left
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x10179
x166
x115
x17
x4

asked: Nov 05, 2011 at 09:11 PM

Seen: 6972 times

Last Updated: Nov 22, 2011 at 03:05 PM