Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to handle Unity re-assigning touches?

Discussion in 'Scripting' started by _Adriaan, Jul 21, 2012.

  1. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    481
    Hello friendly people,

    I am working on a prototype that contains entities that need to know to which Touch they are bound to.

    For example, I put down four fingers. In code, those would be touches[0-3]. Now: if I take away my third finger, Unity will automatically assign touch[3] to touch[2] and nullify touch[3]. Code doesn't tell me which finger was let go, it just takes one away - and I'm stuck with one entity that is looking for a touch that doesn't exist and one entity that is taken over by a different finger!

    How I handled this in the past was to never bind the actual touches with the entities, determining every single frame which was bound to which. I ray-cast from each touch position on the screen to the world - every frame, with every touch. That works fine, unless you move the touch so fast that the collision below it isn't updated quickly enough or you aren't using colliders. The last thing is the case in my current prototype: I have no collision on the thing I'm 'dragging,' if the concept of dragging is applicable at all.

    So my question is as following: how do you (or would you) keep track of which touch is which and connect them to an entity?

    Thank you for your time.
     
    Last edited: Jul 21, 2012
  2. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    This is 1:1 with how iOS handles it.... in short you write a touch manager (there are many, many free ones available if you search).

    What you do is loop through touches and respond to the events such as began, ended and so forth, and if something begins you add it to your list, and track it in your list, and when it ends you delete it from your list. You don't use array indexes to decide if it exists or not.
     
  3. _Adriaan

    _Adriaan

    Joined:
    Nov 12, 2009
    Posts:
    481
    Of course! I was so focussed on the indexes... You are a genius. Thank you.
     
  4. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    I would prefer if it was fixed to an index , because I dont want to have to add and delete items from a list all the time.

    Is it the same on android? if so ,can someone explain to me the benefit of having it work this way. I dont know how it works internally , but surely it makes more sense to cache a touch object in an array and update fields on that object. then just pass the reference to that array back to us. I know the docs mention getTouch not allocating memory , not sure how that ties into what im suggesting in a good or bad way.
     
    Last edited: Jul 21, 2012
  5. Tseng

    Tseng

    Joined:
    Nov 29, 2010
    Posts:
    1,217
    Because there is no way to tell when a user removes a finger and puts it back on the screen to tell if it's the same or a new finger.

    Also, the touches is a an array and it's size is the indicator on how many touches are active. If you have an array of touches[5] but only 3 fingers, you wouldn't know which of the 5 elements contains a finger and which not and you would have to do additional if(touches[index]!=null touches[index].phase==...) check. Now you know that if the touches array is > 0 then you know that the elements can NEVER EVER be null and you don't have to do null checks.

    Also since you don't know if a user re-touches with the same or a new finger, you would have to increase that array indefinitely until no touches are there.

    i.e. 2 fingers
    touches[0] = finger 1
    touches[1] = finger 2

    user removes finger 1
    touches[0] = null
    touches[1] = finger 2

    user adds finger
    touches[0] = null
    touches[1] = finger 2
    touches[2] = finger 3

    etc. which makes no sense at all.

    If it would fill out the nulled ones, then you'd have
    touches[0] = finger 3
    touches[1] = finger 2

    confusing isn't it? That the 3rd finger is in 0 array?
     
  6. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
    Thanks Tseng

    I understand the pros in that if touchCount > 0 then nothing is null and shorter loop lengths are useful if less than 5 fingers are been used etc. I personally have a working solution using a dictionary and fingerIDs as keys to not have to add/remove items from a list to track my touches.

    Just for fun let me show you my logic in regards to your examples on how it could work with fixed indexes :

    Firstly if a finger is removed - its removed. - there is no concern with whether its a new finger or the same as you described. The logic rule for a new touch is to use the lowest available index and skip in use indexes

    Secondly I wouldn't expect any index to ever be null , rather , each index is a Touch object (same object as currently returned by calls to GetTouch )
    this touch object should have an an additional phase enum value of say "NONE" .. so you can only check that



    then in your example :


    i.e. 2 fingers
    touches[0].phase = TouchPhase.Began;
    touches[1].phase = TouchPhase.Began;
    touches[2].phase = TouchPhase.None;
    touches[3].phase = TouchPhase.None;
    touches[4].phase = TouchPhase.None;

    user removes finger 1
    touches[0].phase = TouchPhase.Ended;
    touches[1].phase = *any of the expected TouchPhase values Stationary or Moved
    touches[2].phase = TouchPhase.None;
    touches[3].phase = TouchPhase.None;
    touches[4].phase = TouchPhase.None;

    after one frame if no new touches then position 0 is reset

    touches[0].phase = TouchPhase.None;
    touches[1].phase = *any of the expected TouchPhase values Stationary or Moved
    touches[2].phase = TouchPhase.None;
    touches[3].phase = TouchPhase.None;
    touches[4].phase = TouchPhase.None;


    user adds finger :

    This starts at the lowest available value and skips in use values :


    touches[0].phase = TouchPhase.Began;
    touches[1].phase = *any of the expected TouchPhase values Stationary or Moved
    touches[2].phase = TouchPhase.None;
    touches[3].phase = TouchPhase.None;
    touches[4].phase = TouchPhase.None;

    This logic seems sound and in regards to the OP concern for mapping to his entities it would work perfectly , i think haaha.