duck

Index - Mobile Joystick With Tap Control

Oct 4th, 2012
221
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.55 KB | None | 0 0
  1. using UnityEngine;
  2.  
  3. [RequireComponent (typeof(GUITexture))]
  4.  
  5. public class Boundary {
  6.     public Vector2 min = Vector2.zero;
  7.     public Vector2 max = Vector2.zero;
  8. }
  9.    
  10. public class Joystick : MonoBehaviour
  11. {
  12.     static private Joystick[] joysticks;                    // A static collection of all joysticks
  13.     static private bool enumeratedJoysticks = false;
  14.     static private float tapTimeDelta = 0.3f;               // Time allowed between taps
  15.    
  16.    
  17.     public bool touchPad;                                   // Is this a TouchPad?
  18.     public Rect touchZone;
  19.     public float deadZone = 0;                                  // Control when position is output
  20.     public bool normalize = false;                          // Normalize output after the dead-zone?
  21.     public Vector2 position;                                // [-1, 1] in x,y
  22.     int tapCount;                                           // Current tap count
  23.    
  24.     public bool touched { get; private set; }
  25.    
  26.     private int lastFingerId = -1;                              // Finger last used for this joystick
  27.     private float tapTimeWindow;                            // How much time there is left for a tap to occur
  28.     private Vector2 fingerDownPos;
  29.     private float fingerDownTime;
  30.     private float firstDeltaTime = 0.5f;
  31.    
  32.     private GUITexture gui;                             // Joystick graphic
  33.     private Rect defaultRect;                               // Default position / extents of the joystick graphic
  34.     private Boundary guiBoundary = new Boundary ();         // Boundary for joystick graphic
  35.     private Vector2 guiTouchOffset;                     // Offset to apply to touch input
  36.     private Vector2 guiCenter;                          // Center of joystick
  37.    
  38.     #if !UNITY_IPHONE && !UNITY_ANDROID
  39.    
  40.     void Awake () {
  41.         gameObject.active = false; 
  42.     }
  43.    
  44.     #else
  45.    
  46.     void Start () {
  47.         // Cache this component at startup instead of looking up every frame   
  48.         gui = GetComponent<GUITexture> ();
  49.        
  50.         // Store the default rect for the gui, so we can snap back to it
  51.         defaultRect = gui.pixelInset;  
  52.            
  53.         defaultRect.x += transform.position.x * Screen.width;// + gui.pixelInset.x; // -  Screen.width * 0.5;
  54.         defaultRect.y += transform.position.y * Screen.height;// - Screen.height * 0.5;
  55.        
  56.         Vector3 tPos = transform.position;
  57.         tPos.x = 0;
  58.         tPos.y = 0;
  59.        
  60.         transform.position = tPos;
  61.            
  62.         if (touchPad) {
  63.             // If a texture has been assigned, then use the rect ferom the gui as our touchZone
  64.             if (gui.texture)
  65.                 touchZone = defaultRect;
  66.         }
  67.         else {             
  68.             // This is an offset for touch input to match with the top left
  69.             // corner of the GUI
  70.             guiTouchOffset.x = defaultRect.width * 0.5f;
  71.             guiTouchOffset.y = defaultRect.height * 0.5f;
  72.            
  73.             // Cache the center of the GUI, since it doesn't change
  74.             guiCenter.x = defaultRect.x + guiTouchOffset.x;
  75.             guiCenter.y = defaultRect.y + guiTouchOffset.y;
  76.            
  77.             // Let's build the GUI boundary, so we can clamp joystick movement
  78.             guiBoundary.min.x = defaultRect.x - guiTouchOffset.x;
  79.             guiBoundary.max.x = defaultRect.x + guiTouchOffset.x;
  80.             guiBoundary.min.y = defaultRect.y - guiTouchOffset.y;
  81.             guiBoundary.max.y = defaultRect.y + guiTouchOffset.y;
  82.         }
  83.     }
  84.    
  85.     void Disable () {
  86.         gameObject.active = false;
  87.         enumeratedJoysticks = false;
  88.     }
  89.    
  90.     void ResetJoystick () {
  91.         // Release the finger control and set the joystick back to the default position
  92.         gui.pixelInset = defaultRect;
  93.         lastFingerId = -1;
  94.         position = Vector2.zero;
  95.         fingerDownPos = Vector2.zero;
  96.        
  97.         if (touchPad){
  98.             Color guiCol = gui.color;
  99.             guiCol.a = 0.025f;
  100.             touched = false;
  101.             gui.color = guiCol;
  102.         }
  103.                
  104.     }
  105.    
  106.     bool IsFingerDown ()  {
  107.         return (lastFingerId != -1);
  108.     }
  109.        
  110.     void LatchedFinger (int fingerId) {
  111.         // If another joystick has latched this finger, then we must release it
  112.         if (lastFingerId == fingerId)
  113.             ResetJoystick ();
  114.     }
  115.    
  116.     void Update () {
  117.        
  118.         if (!enumeratedJoysticks) {
  119.             // Collect all joysticks in the game, so we can relay finger latching messages
  120.             joysticks = (Joystick[])FindObjectsOfType (typeof(Joystick));
  121.             enumeratedJoysticks = true;
  122.         }  
  123.            
  124.         var count = Input.touchCount;
  125.        
  126.         // Adjust the tap time window while it still available
  127.         if (tapTimeWindow > 0)
  128.             tapTimeWindow -= Time.deltaTime;
  129.         else
  130.             tapCount = 0;
  131.        
  132.         if (count == 0) {
  133.             ResetJoystick ();
  134.            
  135.         }
  136.         else {
  137.             for (int i = 0; i < count; i++) {
  138.                 Touch touch  = Input.GetTouch (i);         
  139.                 Vector2 guiTouchPos  = touch.position - guiTouchOffset;
  140.        
  141.                 var shouldLatchFinger = false;
  142.                 touched = false;
  143.                 if (touchPad) {            
  144.                     if (touchZone.Contains (touch.position))
  145.                         shouldLatchFinger = true;
  146.                        
  147.                 }
  148.                 else if (gui.HitTest (touch.position)) {
  149.                     shouldLatchFinger = true;
  150.                    
  151.                 }
  152.        
  153.                 // Latch the finger if this is a new touch
  154.                 if (shouldLatchFinger && (lastFingerId == -1 || lastFingerId != touch.fingerId)) {
  155.                    
  156.                     if (touchPad) {
  157.                         Color guiCol = gui.color;
  158.                         touched = true;
  159.                         guiCol.a = 0.15f;
  160.                         gui.color = guiCol;
  161.                        
  162.                         lastFingerId = touch.fingerId;
  163.                         fingerDownPos = touch.position;
  164.                         fingerDownTime = Time.time;
  165.                     }
  166.                    
  167.                     lastFingerId = touch.fingerId;
  168.                    
  169.                     // Accumulate taps if it is within the time window
  170.                     if (tapTimeWindow > 0) {
  171.                         tapCount++;
  172.                     }
  173.                     else {
  174.                         tapCount = 1;
  175.                         tapTimeWindow = tapTimeDelta;
  176.                     }
  177.                                                
  178.                     // Tell other joysticks we've latched this finger
  179.                     foreach (var j in joysticks) {
  180.                         if (j != null && j != this)
  181.                             j.LatchedFinger (touch.fingerId);
  182.                     }                      
  183.                 }              
  184.        
  185.                 if (lastFingerId == touch.fingerId) {
  186.                     // Override the tap count with what the iPhone SDK reports if it is greater
  187.                     // This is a workaround, since the iPhone SDK does not currently track taps
  188.                     // for multiple touches
  189.                     if (touch.tapCount > tapCount)
  190.                         tapCount = touch.tapCount;
  191.                    
  192.                     if (touchPad) {
  193.                         // For a touchpad, let's just set the position directly based on distance from initial touchdown
  194.                         position.x = Mathf.Clamp ((touch.position.x - fingerDownPos.x) / (touchZone.width / 2), -1, 1);
  195.                         position.y = Mathf.Clamp ((touch.position.y - fingerDownPos.y) / (touchZone.height / 2), -1, 1);
  196.                     }
  197.                     else {                 
  198.                         // Change the location of the joystick graphic to match where the touch is
  199.                         position.x = (touch.position.x - guiCenter.x) / guiTouchOffset.x;
  200.                         position.y = (touch.position.y - guiCenter.y) / guiTouchOffset.y;
  201.                     }
  202.                    
  203.                     if (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled)
  204.                         ResetJoystick ();
  205.                 }          
  206.             }
  207.         }
  208.        
  209.         // Calculate the length. This involves a squareroot operation,
  210.         // so it's slightly expensive. We re-use this length for multiple
  211.         // things below to avoid doing the square-root more than one.
  212.         float length  = position.magnitude;
  213.        
  214.        
  215.         if (length < deadZone) {
  216.             // If the length of the vector is smaller than the deadZone radius,
  217.             // set the position to the origin.
  218.             position = Vector2.zero;
  219.         }
  220.         else {
  221.             if (length > 1) {
  222.                 // Normalize the vector if its length was greater than 1.
  223.                 // Use the already calculated length instead of using Normalize().
  224.                 position = position / length;
  225.             }
  226.             else if (normalize) {
  227.                 // Normalize the vector and multiply it with the length adjusted
  228.                 // to compensate for the deadZone radius.
  229.                 // This prevents the position from snapping from zero to the deadZone radius.
  230.                 position = position / length * Mathf.InverseLerp (length, deadZone, 1);
  231.             }
  232.         }
  233.        
  234.         if (!touchPad) {
  235.             // Change the location of the joystick graphic to match the position
  236.             Rect pi = gui.pixelInset;
  237.             pi.x = (position.x - 1) * guiTouchOffset.x + guiCenter.x;
  238.             pi.y = (position.y - 1) * guiTouchOffset.y + guiCenter.y;
  239.             gui.pixelInset = pi;
  240.         }
  241.     }
  242.    
  243.     #endif
  244.    
  245. }
Advertisement
Add Comment
Please, Sign In to add comment