Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by gebnar · Nov 17, 2011 at 03:04 AM · androidinputbugtouch

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

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

3 Replies

· Add your reply
  • Sort: 
avatar image
3

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

}

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image MD_Reptile · May 10, 2012 at 03:21 AM 0
Share

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.

avatar image
2

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

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
2

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);
     }
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image MD_Reptile · Dec 21, 2014 at 10:08 AM 0
Share

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

Hint: You can notify a user about this post by typing @username

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

Answers Answers and Comments

4 People are following this question.

avatar image avatar image avatar image avatar image

Related Questions

Infuriating bug: Android build occasionally dropping touch input. 0 Answers

Android: Touch Input Timeout Issue 1 Answer

Joypad help 0 Answers

Please confirm: Galaxy Stylus not readable directly in Unity 1 Answer

How to differentiate touches on mobile devices 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges