1. We've introduced thread tags, search within a thread and similar thread search. Read more here.
    Dismiss Notice
  2. Learn how you'll soon be able to publish your games to China in four simple steps with Xiaomi. Sign up now for early access.
    Dismiss Notice
  3. Get further faster with the Unity Plus Accelerator Pack, free for new Unity Plus subscribers for a limited time. Click here for more details.
    Dismiss Notice
  4. We've released our first Timeline Experimental Preview, our new tool for creating cutscenes and more! To check it out click here.
    Dismiss Notice
  5. Unity 5.5 is now released.
    Dismiss Notice
  6. Check out all the fixes for 5.5 in patch releases 1 & 2.
    Dismiss Notice
  7. Unity 5.6 beta is now available for download.
    Dismiss Notice

Unity Remote missing TouchPhase.Ended signal sometimes.

Discussion in 'iOS and tvOS' started by Wu Jie, Oct 23, 2010.

  1. Wu Jie

    Wu Jie

    Joined:
    Sep 20, 2010
    Posts:
    704
    Hi,

    I use Unity3 iOs to develop iphone/ipad games. Sometimes I use UnityRemote for rapid play the game in my Mac PC. But when I start using touchPhase features, I found that UnityRemote sometimes missing the Ened phase when you leave your finger from the screen of your iPad. But it works fine if you run the game on iPad.

    I first though it may be something wrong in my script, but when I run this demo in UnityRemote http://blogs.unity3d.com/2009/05/07/my-first-post-and-a-mini-tutorial/, the same issue happens. So I guess it should be problem when using UnityRemote with TouchPhase code?

    Any one have same experience, and have a way to solve it ??
     
  2. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    Never use TouchPhase; it's completely unreliable in every case. (At least that's been my experience; I really wonder how these functions even exist, because its seems like every App would be broken if it did rely on the phases.) I roll my own; here's a relevant except from my Button class:

    Code (csharp):
    1. protected List<HeldTouch> heldTouches;
    2. protected struct HeldTouch {
    3.     public int fingerID;
    4.     public Vector2 position;
    5.    
    6.     public HeldTouch (Touch touch) {
    7.         fingerID = touch.fingerId;
    8.         position = touch.position;
    9.     }
    10. }
    11. protected Rect rect;
    12.  
    13. protected virtual void Awake () {
    14.     heldTouches = new List<HeldTouch>();
    15.     Press += () => Held = true;
    16.     Cancel += () => Held = false;
    17.     Release += () => Held = false;
    18. }
    19.  
    20. protected virtual void Update () { 
    21.     if (Held) {
    22.         fingerIDs.Clear();
    23.         for (int i = 0; i < Input.touchCount; ++i) {
    24.             Touch touch = Input.GetTouch(i);
    25.             fingerIDs.Add(touch.fingerId);
    26.             int heldTouchIndex = heldTouches.FindIndex(
    27.                 heldTouch => touch.fingerId == heldTouch.fingerID);
    28.             if (heldTouchIndex > -1) heldTouches[heldTouchIndex] = new HeldTouch(touch);
    29.             else if (rect.Contains(touch.position)) heldTouches.Add(new HeldTouch(touch));
    30.         }
    31.         heldTouches.RemoveAll(heldTouch => !fingerIDs.Contains(heldTouch.fingerID));
    32.                
    33.         if (Held) {
    34.             heldTouches.RemoveAll(heldTouch => !rect.Contains(heldTouch.position));
    35.             if (!Held) Cancel();
    36.         }
    37.         else Release();
    38.                
    39.         return;
    40.     }
    41.     newFingerIDs.Clear();
    42.     for (int i = 0; i < Input.touchCount; ++i) {
    43.         Touch touch = Input.GetTouch(i);
    44.         newFingerIDs.Add(touch.fingerId);
    45.         // !fingerIDs.Contains(touch.fingerId) is an alternative to TouchPhase.Began,
    46.         // which I don't trust.  ;-P
    47.         if (!fingerIDs.Contains(touch.fingerId)  rect.Contains(touch.position))
    48.             heldTouches.Add(new HeldTouch(touch));
    49.     }
    50.     if (Held) Press();
    51.     fingerIDs.Clear();
    52.     fingerIDs.AddRange(newFingerIDs);
    53. }
    Wow, that's completely unreadable. Copy that into an editor if you're interested.
     
    Last edited: Oct 23, 2010
  3. Wu Jie

    Wu Jie

    Joined:
    Sep 20, 2010
    Posts:
    704
    Oh! Thanks, I'll try your code later.
    I didn't experience buggy case when use TouchPhase in the real device, it seems like they only become untrusted with UnityRemote.

    Anyway, thank you all the same for your advice. I hope Unity-Team notice the problem and have way to solve it!
     
  4. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,035
    You are right. I find TouchPhase to be totally unreliable on Android which makes it practically useless.
    But Jessy, can you post a working example of your class instead of just a snippet?

    I get the error
    "The type or namespace name `List`1' could not be found. Are you missing a using directive or an assembly reference?"
    at this line:
    protected List<HeldTouch> heldTouches;

    Also "newFingerIDs" is missing.
    Thanks.

    EDIT: I added some code which works. It also avoids the use of TouchPhase. But I noticed that even with this code, my screen has a "virtual finger" touching it. Must be a hardware issue...

    Code (csharp):
    1.  
    2. //This code will use a multitouch screen to select an object (one finger) and pinch-to-zoom to scale an object //(cumulative, using two fingers)
    3. //Put this code in a *.js script and attach it to a game object.
    4.  
    5. private var selectedObject : GameObject;
    6. private var selectedObjectTemp : GameObject;
    7. private var amount : float;
    8. private var beginPosSet : boolean = false;
    9. private var screenTouched : boolean = false;
    10. private var pinchPrev : float;
    11. private var pinch : float;
    12. private var pinchCumu : float;
    13.  
    14. function Start(){
    15.     Input.multiTouchEnabled = true;
    16. }
    17.  
    18. function FixedUpdate() {
    19.    
    20.     //make pinch-to-zoom or pinch-to-scale logic
    21.     if(Input.touchCount == 2)
    22.     {
    23.         var touch1 : Touch = Input.GetTouch(0);
    24.         var touch2 : Touch = Input.GetTouch(1);
    25.         var pinchFactor : float;
    26.        
    27.         if(!beginPosSet)
    28.         {
    29.             //store the begin distance
    30.             beginDistance = Vector2.Distance(touch1.position, touch2.position);
    31.             beginPosSet = true;
    32.         }
    33.        
    34.         var currentDistance : float = Vector2.Distance(touch1.position, touch2.position);
    35.         pinch = currentDistance - beginDistance;
    36.        
    37.         //scale is cumulative
    38.         pinchCumu = pinchPrev + pinch;
    39.        
    40.         //Factor the scale-to-be-used. The pinch value will be used to scale an object in this case,
    41.         //so keep it within a sensible range. Note that it is easy to increase the size of an object as
    42.         //that factor is more or less linear. But if you want to decrease the size, you have to keep
    43.         //the scale between about 0.1 and 1.0
    44.         pinchFactor = pinchCumu;
    45.         if(pinchFactor >= 0)
    46.         {
    47.             pinchFactor = (pinchFactor / 10.256f) + 1.0f;
    48.         }
    49.         else
    50.         {
    51.             pinchFactor = (pinchFactor / 400.0) +1.0f;
    52.         }
    53.        
    54.         //clamp
    55.         if(pinchFactor < 0.1f)
    56.         {
    57.             pinchFactor = 0.1f;
    58.         }  
    59.        
    60.         //do something with the cumulative zoom value, like scale an object.
    61.         selectedObject.transform.localScale = Vector3(pinchFactor, 1, 1);
    62.     }
    63.    
    64.     //the user removed one or both fingers
    65.     if(Input.touchCount < 2)
    66.     {
    67.         //reset the beginpos flag
    68.         beginPosSet = false;
    69.        
    70.         //store the pinch value;
    71.         pinchPrev = pinchCumu;
    72.     }
    73.    
    74.     //the user removed the finger, so reset the screenTouched flag
    75.     if(Input.touchCount == 0)
    76.     {
    77.         screenTouched = false;
    78.     }  
    79.    
    80.     //object selection, with one finger.
    81.     if((Input.touchCount == 1)  (!screenTouched))
    82.     {
    83.         var hit : RaycastHit;
    84.          
    85.         if (Physics.Raycast (ray, hit, Mathf.Infinity))
    86.         {
    87.             selectedObjectTemp = hit.transform.gameObject;
    88.  
    89.             //is the selected object a line object?
    90.             if(selectedObjectTemp.tag == "Vector")
    91.             {
    92.                 selectedObject = selectedObjectTemp;
    93.                
    94.                 //do something with the object selected
    95.                 //selectedObject.SendMessage("ChangeColorOfYourObject");
    96.             }
    97.         }  
    98.        
    99.         screenTouched = true;
    100.     }  
    101. }
    102.  
     
    Last edited: May 29, 2011
  5. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    Sure. I'm posting my complete class, which requires other classes in order to construct the button, but it may help you get a better idea of what I did. Unfortunately, the code is based on events, making it currently unsuitable for UnityScript, which can apparently use them, but in which they cannot be defined as of yet.

    You really need to know about the generic List, which is available in Unity's JavaScript now, too, and serves as a successor to Unity's Array class, or ArrayList, in most cases. In JS, you need
    Code (csharp):
    1. import System.Collections.Generic
    at the top of your script, in order to be able to use it.
     

    Attached Files:

  6. Elecman

    Elecman

    Joined:
    May 5, 2011
    Posts:
    1,035
    Ok, thanks.
     
  7. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    4,363
    I've never* had an issue with touch phase on iOS ... maybe on the remote but it has all kinds of weird behaviours, never* on the device.

    EDIT: *I vaguely remember the ended phase not being sent if your finger goes off the edge of the screen, as opposed to being lifted off, but doesn't seem to be happening on any of the projects I have loaded on my phone.
     
    Last edited: May 31, 2011
  8. DanjelRicci

    DanjelRicci

    Joined:
    Mar 8, 2010
    Posts:
    138
    UnityRemote misses almost every touch event, it's tremendously laggy, while on real iOS device everything works perfectly with TouchPhase. :)