- Home /
Panning & Zooming using Multi Touch
Lately I've been trying to make my camera zoom in when pinching and pan when swiping. But I have run into some problems. I know that you need to start with:
if(Input.touchCount == 2) {
//the rest
}
But how can I do the rest? I know you need to calculate distances between your two fingers. But how can you do the rest? Like how can you make sure that pinches don't get confused with swipes.
If anyone has any scripts that I can use, or some way to enlighten me (pseudo code or tuts), that would be great. Thanks!
I´ve never done something like what you need, but I am most certain that you will need to work with touchphases and track their situation along with the touchCount:
http://unity3d.com/support/documentation/ScriptReference/TouchPhase.html
Answer by kromenak · Dec 22, 2011 at 07:38 PM
An easy solution would be to only allow panning with a single touch and switch to zooming when there are two touches.
if(Input.touchCount == 1)
{
PanUpdate();
}
else if(Input.touchCount == 2)
{
ZoomUpdate();
}
If you don't want to go that route, you may have to apply some heuristics to deciding whether the user intends a zoom or a pan. One that might work is to allow a pan when there is one touch. If there are two touches, try to figure out their movement vectors using either touch.position or touch.deltaPosition. If the vectors are pointing in generally the same direction, then it is a pan gesture. If they appear to be opposites or nearly opposites, it is likely a pinch/zoom gesture.
if(Input.touchCount == 1)
{
PanUpdate();
}
else if(Input.touchCount == 2)
{
Vector3 touch1Dir = Input.touches[0].deltaPosition.normalized;
Vector3 touch2Dir = Input.touches[1].deltaPosition.normalized;
float dotProduct = Vector2.Dot(touch1Dir, touch2Dir);
if(dotProduct is near -1) //pinch/zoom
{
ZoomUpdate();
}
else if(dotProduct is near 1) //pan gesture
{
PanUpdate();
}
}
I haven't actually tested this code, so there may be issues with it, but this would be my initial approach to solving this problem. The part that requires playtesting is how near to -1 or 1 the dot product needs to be for the functionality to work correctly.
One finger swipe is taken. So I guess I could do 3 fingers to pan. How would I do that? Calculate the distance from finger points and then use that number to move the camera? $$anonymous$$aybe transform.Translate?
The deltaPosition value of a touch can be translated into camera movement. For a dragging motion, it would seem that you know the direction of the finger movements, so a pan movement is just moving the camera by some speed in the opposite direction of the finger movement.
$$anonymous$$aybe something like: camera.transform.Translate(Input.touches[0].deltaPosition -1 camSpeed$$anonymous$$ultiplier)?
If you want to use the speed of all the fingers at once, you can average them together.
Ok, I got most of it working, but how can I tell when to zoom in and out? I tried calculating but it didn't quite work. Any ideas?
I think you'd need to adjust the camera's field of view for a perspective camera, or the size for an orthographic camera. To detect whether the pinch is inward or outward, it would probably be easiest to calculate the distance between the two touches at each frame. If the distance is smaller than it was last frame, you should zoom in some amount, if larger then zoom out.
currentDistSq = (Input.touches[0].position - Input.touches[1].position).sqr$$anonymous$$agnitude;
if(currentDistSq > prevDistSq + 0.5f) { //zoom out some amount based on (currentDistSq - prevDistSq) } else if(currentDistSq < prevDistSq - 0.5f) { //zoom in some amount based on (currentDistSq - prevDistSq) }
The 0.5f is some margin for error so that the camera doesn't move unless the player does an intentional finger movement. You'll probably have to fiddle with that number to get it just right for your needs.