title: Pinch, and other multi-finger gestures, in modern Unity3D?
body: <p>In modern Unity3D, we use the IPointerDownHandler family of calls.</p>
  <p>Regarding the <code>IPointerDownHandler</code> family of calls,</p>
  <pre><code>public class FingerMove:MonoBehaviour, IPointerDownHandler...
      {
      public void OnPointerDown (PointerEventData data)
          {
  </code></pre>
  <p>Of course they are fantastic</p>
  <h1>for dealing with single touches.</h1>
  <p>But how do you deal with <strong>multiple touches</strong> in a serious way?</p>
  <p>You can &quot;do it all by hand&quot; tracking the touches yourself, but it seems incredible Unity would want you to do that for something so absolutely basic. (I mean - it's a game engine. Sure, I could also write all my own rendering and physics!)</p>
  <p>Here's an example of basically &quot;cowboy programming&quot;, just doing it by hand with no software engineering.  What's the real solution?</p>
  <pre><code>//
  // example of programming a pinch (as well as swipes) using modern Unity
  //
  // here we are forced to track &quot;by hand&quot; in your own code
  // how many fingers are down and which 
  // fingers belong to you etc etc:
  //
  
  // pedagogic example code:
  
  using UnityEngine;
  using UnityEngine.UI;
  using System.Collections;
  using UnityEngine.EventSystems;
  
  public class FingerMove:MonoBehaviour,
           IPointerDownHandler, IDragHandler, IPointerUpHandler
      {
      // these three for the ordinary one-finger-only drag
      private Vector2 prevPoint;
      private Vector2 newPoint;
      private Vector2 screenTravel;
      // and this one is the ordinary one-finger-only drag
      private int currentMainFinger = -1;
      
      // and this for the (strictly second finger only) drag...
      private int currentSecondFinger = -1;
      private Vector2 posA;
      private Vector2 posB;
      
      private float previousDistance = -1f;
      private float distance;
      private float pinchDelta = 0f;
      
      public void OnPointerDown (PointerEventData data)
          {
          if (currentMainFinger == -1)
              {
              // this is the NEW currentMainFinger
              currentMainFinger = data.pointerId;
              prevPoint = data.position;
              
              // and for the drag (if it becomes used)...
              posA = data.position;
              
              return;
              }
          
          if (currentSecondFinger == -1)
              {
              // this is the NEW currentSecondFinger
              currentSecondFinger = data.pointerId;
              posB = data.position;
              
              figureDelta();
              previousDistance = distance;
              
              return;
              }
          
          Debug.Log(&quot;third+ finger! (ignore)&quot;);
          }
  
      public void OnDrag (PointerEventData data)
          {
          // handle single-finger moves (swipes, drawing etc) only:
          
          if ( currentMainFinger == data.pointerId )
              {
              newPoint = data.position;
              screenTravel = newPoint - prevPoint;
              prevPoint = newPoint;
              
              if (currentSecondFinger == -1)
                  {
                  Debug.Log(&quot;NO 2f&quot;);
                  _processSwipe(); // handle it your way
                  }
              else
                  {
                  }
              
              // and for two-finger if it becomes used next frame
              // or is already being used...
              posA = data.position;
              }
          
          if (currentSecondFinger == -1) return;
          
          // handle two-finger (eg, pinch, rotate etc)...
          
          if ( currentMainFinger == data.pointerId ) posA = data.position;
          if ( currentSecondFinger == data.pointerId ) posB = data.position;
          
          figureDelta();
          pinchDelta =  distance - previousDistance;
          previousDistance = distance;
          
          _processPinch(); // handle it your way
          }
      
      private void figureDelta()
          {
          // when/if two touches, keep track of the distance between them
          distance = Vector2.Distance(posA, posB);
          }
      
      public void OnPointerUp (PointerEventData data)
          {
          if ( currentMainFinger == data.pointerId )
              {
              currentMainFinger = -1;
              }
          if ( currentSecondFinger == data.pointerId )
              {
              currentSecondFinger = -1;
              }
          }
      
      private float sensitivity = 0.3f;
      
      // in this example, the swipes/pinch affects these three calls:
      public Changer orbitLR;
      public Changer orbitUD;
      public Changer distanceZ;
      // initial values of those...
      private float LR = -20f;
      private float UD = 20f;
      private float distanceCam = 5f;
      
      private void _processSwipe()
          {
          // in this example, just left-right or up-down swipes
          
          LR = LR + sensitivity * screenTravel.x;
          UD = UD - sensitivity * screenTravel.y;
          
          LR = Mathf.Clamp(LR, -150f, 30f);
          UD = Mathf.Clamp(UD, 5f, 50f);
          
          orbitLR.RotationY = LR;
          orbitUD.RotationX = UD;
          }
      
      private void _processPinch()
          {
          // in this example, pinch to zoom
          
          distanceCam = distanceCam - pinchDelta * 0.0125f;
          distanceCam = Mathf.Clamp(distanceCam, 3f, 8f);
          distanceZ.DistanceZ = distanceCam;
          }
      
      }
  </code></pre>
  <p>(Note, please do not answer regarding the legacy &quot;Touches&quot; system which is unusable. This about normal modern Unity development.)</p>