- Home /
TouchPhase not firing correctly - Android
On my Android device, everything seem to work correctly the first time I load up my app, but if I switch to another application and back, the TouchPhase.began, and TouchPhase.ended phases simply do not fire most of the time, which makes my game unplayable.
Does anyone have a suggestion for how I can fix this problem, or how I can get around it?
Here's the code I've been using to track if the user touches a GUITexture:
function Update(){
    for(var i : int = 0; i < Input.touchCount; i++){
        var touch : Touch = Input.GetTouch(i);
        if(touch.phase == TouchPhase.Began && guiTexture.HitTest(touch.position)){
            DoSomething();
        }
    }
}
 
                
               Any help would be MUCH appreciated! Many thanks in advance if you can solve this problem for me. =D
Answer by gebnar · Jan 11, 2012 at 02:31 PM
OK... I've come up with a second solution for this problem, this time on a more global scale. Essentially, I have provided a replacement for the Input.touches array using a static class and a single script that can be attached to any GameObject in the scene. Here are the scripts:
First, the static class, you don't need an instance of this class anywhere. Just have it in your project.
Touches.csusing UnityEngine; using System.Collections;
public static class Touches : object { static public FakeTouch[] touches; static public int touchCount;
static public FakeTouch GetTouch(int index){ if(index < touches.Length){ return touches[index]; }else{ return new FakeTouch(); } }}
Second, the script. Attach this to any object in each scene in which you want to access the alternative touches array.
TouchHandler.csusing UnityEngine; using System.Collections;
//public enum TouchState {Began,Stationary,Moved,Ended}
public struct FakeTouch { public int fingerId; public Vector2 position; public Vector2 deltaPosition; public float deltaTime; public int tapCount; public TouchPhase phase; public Touch realTouch;
public FakeTouch(int id, Vector2 pos, Vector2 dPos, float dTime, int taps, TouchPhase tPhase, Touch touch){ fingerId = id; position = pos; deltaPosition = dPos; deltaTime = dTime; tapCount = taps; phase = tPhase; realTouch = touch; }}
public class TouchHandler : MonoBehaviour { // public GUIText gText;
void Start() { Touches.touches = new FakeTouch[0]; Touches.touchCount = 0; } void Update(){ FakeTouch[] oldTouches = Touches.touches; Touch[] newTouches = Input.touches; bool[] usedTouches = new bool[newTouches.Length]; FakeTouch[] touchList = new FakeTouch[100]; //initialize new Touch array int index = 0; //new touch array index //first iterate through old touches, and update any changed values for(int ot = 0; ot < oldTouches.Length; ot++){ //any touch with phase ended can be ignored if(oldTouches[ot].phase != TouchPhase.Ended){ //this touch needs to be added to the array bool updated = false; //iterate through new touches, checking for same ID for(int nt = 0; nt < newTouches.Length; nt++){ if(oldTouches[ot].fingerId == newTouches[nt].fingerId){ //id's are a match, update old touch and add it to array touchList[index] = UpdateTouch(oldTouches[ot],newTouches[nt]); index++; //keep track of newTouches that we already added into the array usedTouches[nt] = true; //we found the matching touch, no need to keep checking stuff updated = true; break; } } if(!updated){ //if there was no corresponding new touch, add this touch to the array as Ending touchList[index] = EndTouch(oldTouches[ot]); index++; } } }//finished iterating through old touches //now iterate through new touches for(int nt = 0; nt < newTouches.Length; nt++){ //check if this touch was already used if(!usedTouches[nt]){ //touch hasn't been added yet touchList[index] = StartTouch(newTouches[nt]); index++; } }//finished iterating through new touches //now put all collected touches into a small array Touches.touches = new FakeTouch[index]; for(int i = 0; i < index; i++){ Touches.touches[i] = touchList[i]; } //set touchCount Touches.touchCount = index; } private FakeTouch StartTouch(Touch newTouch){ return new FakeTouch( /*fingerId*/newTouch.fingerId, /*position*/newTouch.position, /*deltaPosition*/newTouch.deltaPosition, /*deltaTime*/newTouch.deltaTime, /*tapCount*/newTouch.tapCount, /*phase*/TouchPhase.Began, /*realTouch*/newTouch); } private FakeTouch UpdateTouch(FakeTouch oldTouch, Touch newTouch){ TouchPhase phase; if(oldTouch.position == newTouch.position){ phase = TouchPhase.Stationary; }else{ phase = TouchPhase.Moved; } return new FakeTouch( /*fingerId*/newTouch.fingerId, /*position*/newTouch.position, /*deltaPosition*/newTouch.deltaPosition, /*deltaTime*/newTouch.deltaTime, /*tapCount*/newTouch.tapCount, /*phase*/phase, /*realTouch*/newTouch); } private FakeTouch EndTouch(FakeTouch oldTouch){ return new FakeTouch( /*fingerId*/oldTouch.fingerId, /*position*/oldTouch.position, /*deltaPosition*/oldTouch.deltaPosition, /*deltaTime*/oldTouch.deltaTime, /*tapCount*/oldTouch.tapCount, /*phase*/TouchPhase.Ended, /*realTouch*/oldTouch.realTouch); }}
oh man, you are awesome. this is an awesome solution, far better than the POS one I had hacked together. if I could give you $$anonymous$$ORE thumbs up, I absolutely would man.
Answer by gebnar · Nov 17, 2011 at 01:28 PM
In case anyone else runs into this problem, I've come up with the following code tidbit that lets me track TouchPhases in my own way, and has an easy-to-access event handler section.
Still, If anyone has an actual solution to the basic problem of TouchPhases not firing correctly, I would like to see a proper answer posted here.
private var fingerLatched:boolean; private var latchedId:int; private var latchedPosition:Vector2; private var button:GUITexture; private var touchState:TouchState;
enum TouchState { Idle = 0, Began = 1, Stationary = 2, Moving = 3, Ended = 4, }
//custom variables //end custom variables
function TouchHandler(){ //custom event handler if(touchState == TouchState.Began){ DoSomething(); } //end custom event Handler }
function Start(){ //custom start code //end custom start code button = GetComponent( GUITexture ); fingerLatched = false; latchedId = -1; touchState = TouchState.Idle; latchedPosition = Vector2.zero; }
function Update(){ //custom update code //end custom update code touchState = TouchState.Idle; for(var i:int = 0; i < Input.touchCount; i++){ var touch:Touch = Input.GetTouch(i); var touchPos:Vector2 = touch.position;
     if( button.HitTest(touch.position) ){
         //button is being touched
         if(fingerLatched){
             //finger is latched
             if(touch.fingerId == latchedId){
                 //being touched by same finger
                 if(touch.position == latchedPosition){
                     //touch is stationary
                     touchState = TouchState.Stationary;
                 }else{
                     //touch is moving
                     touchState = TouchState.Moving;
                     //update latched position for next frame
                     latchedPosition = touch.position;
                 }
             }else{
                 //being touched by extra finger
             }
         }else{
             //no finger is latched
             latchFinger(touch);
             touchState = TouchState.Began;
         }
     }
 }
 if(touchState == TouchState.Idle && fingerLatched){
     //touch just ended (latched finger either left the button, or stopped
     //touching the screen)
     unLatch();
     touchState = TouchState.Ended;
 }
 
 if(touchState != TouchState.Idle){
     //button is being touched, or touch just ended...
     TouchHandler();
 }
}
function latchFinger(touch:Touch){ //latch the current finger fingerLatched = true; latchedId = touch.fingerId; latchedPosition = touch.position; }
function unLatch(){ //release the latch fingerLatched = false; latchedId = -1; latchedPosition = Vector2.zero; }
Answer by Maddogc · Dec 08, 2012 at 03:34 PM
First of all MAAAN your solution is awesome :D thnx a lot!!! I ran Unity's Profiler and found out that the array allocations at start of Update have a hard impact on GC. So I cached them on Lists and GC is now fine. And here is the appropriate modification of your solution:
 using UnityEngine;
 using System;
 using System.Collections;
 using System.Collections.Generic;
 
 public class TouchHandler : MonoBehaviour 
 { 
     private int _Index;    
     
     private List<bool> _UsedTouchesList     = new List<bool>();
     private List<FakeTouch> _OldTouchesList = new List<FakeTouch>();
     private List<FakeTouch> _TouchList        = new List<FakeTouch>();
     private List<Touch> _NewTouchesList        = new List<Touch>();
     
     private FakeTouch[] _InitTouchArray;
     
     void Start() 
     {
         Touches.touches = new FakeTouch[0];
         Touches.touchCount = 0;
         
         _InitTouchArray = new FakeTouch[100];
     }
     
     void Update()
     {
         ClearLists();
 
         _OldTouchesList.AddRange(Touches.touches);
         _NewTouchesList.AddRange(Input.touches);
         _UsedTouchesList.AddRange(new bool[_NewTouchesList.Count]);
         _TouchList.AddRange(_InitTouchArray); //initialize new Touch array with preinitialized array
         _Index = 0; //new touch array index    
         
         //first iterate through old touches, and update any changed values
         for(int ot = 0; ot < _OldTouchesList.Count; ot++)
         {
             //any touch with phase ended can be ignored
                if(_OldTouchesList[ot].phase != TouchPhase.Ended)
             {
                 //this touch needs to be added to the array
                 bool updated = false;
              
                  //iterate through new touches, checking for same ID
                 for(int nt = 0; nt < _NewTouchesList.Count; nt++)
                 {    
                     if(_OldTouchesList[ot].fingerId == _NewTouchesList[nt].fingerId)
                     {
                         //id's are a match, update old touch and add it to array
                         _TouchList[_Index] = UpdateTouch(_OldTouchesList[ot],_NewTouchesList[nt]);
                         _Index++;                        
                          
                         //keep track of _NewTouchesList that we already added into the array
                         _UsedTouchesList[nt] = true;
                         //we found the matching touch, no need to keep checking stuff
                         updated = true;
                         break;              
                     }             
                 }
                              
                 if(!updated)
                 {
                   //if there was no corresponding new touch, add this touch to the array as Ending
                   _TouchList[_Index] = EndTouch(_OldTouchesList[ot]);
                   _Index++;                 
                 }
             }
         }//finished iterating through old touches
         
         //now iterate through new touches
         for(int nt = 0; nt < _NewTouchesList.Count; nt++)
         {
                //check if this touch was already used           
             if(!_UsedTouchesList[nt])
             {
              //touch hasn't been added yet
              _TouchList[_Index] = StartTouch(_NewTouchesList[nt]);
              _Index++;
             }
         }//finished iterating through new touches
        
         //now put all collected touches into a small array
         Touches.touches = new FakeTouch[_Index];
         
         for(int i = 0; i < _Index; i++)
         {
            Touches.touches[i] = _TouchList[i];
         }
         
         //set touchCount
         Touches.touchCount = _Index;    
     }
     
     private void ClearLists ()
     {
         _OldTouchesList.Clear();
         _NewTouchesList.Clear();
         _UsedTouchesList.Clear();
         _TouchList.Clear();
     }
     
     private FakeTouch StartTouch(Touch newTouch)
     {  
         return new FakeTouch(
        /*fingerId*/newTouch.fingerId,
        /*position*/newTouch.position,
        /*deltaPosition*/newTouch.deltaPosition,
        /*deltaTime*/newTouch.deltaTime,
        /*tapCount*/newTouch.tapCount,
        /*phase*/TouchPhase.Began,
        /*realTouch*/newTouch);
     }
 
     private FakeTouch UpdateTouch(FakeTouch oldTouch, Touch newTouch)
     {
         TouchPhase phase;
         
         if(oldTouch.position == newTouch.position)
         {
            phase = TouchPhase.Stationary;
         }
         else
         {
            phase = TouchPhase.Moved;
         }
         
         return new FakeTouch(
            /*fingerId*/newTouch.fingerId,
            /*position*/newTouch.position,
            /*deltaPosition*/newTouch.deltaPosition,
            /*deltaTime*/newTouch.deltaTime,
            /*tapCount*/newTouch.tapCount,
            /*phase*/phase,
            /*realTouch*/newTouch);
     }
 
     private FakeTouch EndTouch(FakeTouch oldTouch)
     { 
         return new FakeTouch(
        /*fingerId*/oldTouch.fingerId,
        /*position*/oldTouch.position,
        /*deltaPosition*/oldTouch.deltaPosition,
        /*deltaTime*/oldTouch.deltaTime,
        /*tapCount*/oldTouch.tapCount,
        /*phase*/TouchPhase.Ended,
        /*realTouch*/oldTouch.realTouch);
     }
 }
Thanks @$$anonymous$$addogc for the contribution to this answer! $$anonymous$$uch appreciated, however you did forget to include the first part of touchhandler.cs, the part that declares "FakeTouch" - so after "using System.Collections.Generic;" and before "public class TouchHandler : $$anonymous$$onoBehavior" you must include this part:
 public struct FakeTouch { public int fingerId; public Vector2 position; public Vector2 deltaPosition; public float deltaTime; public int tapCount; public TouchPhase phase; public Touch realTouch;
     
     public FakeTouch(int id, Vector2 pos, Vector2 dPos, float dTime, int taps, TouchPhase tPhase, Touch touch){
         fingerId = id;
         position = pos;
         deltaPosition = dPos;
         deltaTime = dTime;
         tapCount = taps;
         phase = tPhase;
         realTouch = touch;
     }
 }
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                