x


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

more ▼

asked Nov 17 at 03:04 AM

gebnar\'s gravatar image

gebnar
16 1 1 1

(comments are locked)
10|3000 characters needed characters left
 moderation talk

2 answers:

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.cs

using 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.cs

using 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);
}

}

more ▼

answered Jan 11 at 02:31 PM

gebnar\'s gravatar image

gebnar
16 1 1 1

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 MORE thumbs up, I absolutely would man.

6 days ago MDReptile
(comments are locked)
10|3000 characters needed characters left
 moderation talk

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;
}
more ▼

answered Nov 17 at 01:28 PM

gebnar\'s gravatar image

gebnar
16 1 1 1

(comments are locked)
10|3000 characters needed characters left
 moderation talk
Your answer
toggle preview:

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Topics:

x1704
x1214
x559
x325
x289

Asked: Nov 17 at 03:04 AM

Seen: 926 times

Last Updated: Nov 17 at 01:28 AM

powered by Qato - Enterprise Q&A