0

I'm creating a touch controlled game that rotates platforms as you touch and drag however I can't get it to ignore touches over the jump button causing it to think that you've very quickly moved the same finger over it as one long swipe. I've tried tracking the start point and id however I've realised that none of these will work without a way to detect whether the touch is over the jump button.

My code for detecting touches:

int x = 0;
        while (x < Input.touchCount)
        {
            Touch touch = Input.GetTouch(x); // get the touch
            if (touch.phase == TouchPhase.Began) //check for the first touch
            {
                fp = touch.position;
                lp = touch.position;
            }
            else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
            {
                lp = touch.position;
            }
            else if (touch.phase == TouchPhase.Ended) //check if the finger is removed from the screen
            {
                lp = touch.position;  //last touch position. Ommitted if you use list

            }
            if (!EventSystem.current.IsPointerOverGameObject(x))
            {
                int movement = ((int)(fp.x - lp.x));
                if (previous_fp != fp ^ x != previous_id)
                {
                    previous_rotate = 0;
                }
                previous_fp = fp;
                previous_id = x;
                if (!game_over) { Platform_Control.transform.Rotate(0f, 0f, -((movement - previous_rotate) * 0.15f), Space.World); }
                previous_rotate = movement;
            }
            x++;
        }
derHugo
  • 83,094
  • 9
  • 75
  • 115
Bob
  • 48
  • 5

3 Answers3

1

Afaik one issue here is that you are using x the index of the touch. IsPointerOverGameObject expects a fingerID as parameter!

The index x of the touch you use for GetTouch is NOT necessarily equal to the Touch.fingerId!

It should rather be

if(!EventSystem.current.IsPointerOverGameObject(touch.fingerId))

Btw in general if you are going to iterate through all touches anyway it is easier to just use Input.touches

Returns list of objects representing status of all touches during last frame. (Read Only) (Allocates temporary variables).

var touches = Input.touches;

which allows you to filter touches out right away like e.g.

using System.Linq;

...


var touches = Input.touches;
var validTouches = touches.Where(touch => !EventSystem.current.IsPointerOverGameObject(touch.fingerId));
foreach(var touch in validTouches)
{
    ...
}

this is using Linq Where and basically equals doing

var touches = Input.touches;
foreach(var touch in touchs)
{
    if(!EventSystem.current.IsPointerOverGameObject(touch.fingerId)) continue;

    ...
}

In general it still confuses me how/why it is supposed to use the same shared variables fp and lp for all possible touches.

You should probably rather use the

var moved = touch.deltaPosition;

And work with that value instead.

Or in general use only one of these touches by storing the first valid touch.fingerId and later check if the touch is still of that id. Ignore all other touches meanwhile.

private int currentFingerId = int.MinValue;

...

// If you check that one first you can avoid a lot of unnecessary overhead ;)
if(!gameOver)
{   
    var touches = Input.touches;
    var validTouches = touches.Where(touch => !EventSystem.current.IsPointerOverGameObject(touch.fingerId);
    foreach (var touch in validTouches)
    {
        if(currentFingerId != int.MinValue && touch.fingerId != currentFingerId) continue;

        switch(touch.phase)
        {
            case TouchPhase.Began:
                currentFingerId = touch.fingerId;
                break;

            case TouchPhass.Moved:
                // "touch.deltaPosition.x" is basically exactly what you calculated
                // yourself using the "fp", "lp", "previous_rotate" and "movement"
                var moved = touch.deltaPosition.x * 0.15f;
                Platform_Control.transform.Rotate(0f, 0f, moved, Space.World);
                break;

            case TouchPhase.Ended:
                currentFingerId = int.MinValue;
                break;
        }
    }
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
0

Check if the EventSystem has any GameObject currently considered as active. If yes, the touch is performed over button else the touch is not over the button.

int x = 0;
while (x < Input.touchCount)
{
    Touch touch = Input.GetTouch(x); // get the touch
    if (touch.phase == TouchPhase.Began) //check for the first touch
    {
        fp = touch.position;
        lp = touch.position;
    }
    else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
    {
        lp = touch.position;
    }
    else if (touch.phase == TouchPhase.Ended) //check if the finger is removed from the screen
    {
        lp = touch.position;  //last touch position. Ommitted if you use list
    }
    if (EventSystem.current.currentSelectedGameObject == null)
    {
        int movement = ((int)(fp.x - lp.x));
        if (previous_fp != fp ^ x != previous_id)
        {
            previous_rotate = 0;
        }
        previous_fp = fp;
        previous_id = x;
        if (!game_over) { Platform_Control.transform.Rotate(0f, 0f, -((movement - previous_rotate) * 0.15f), Space.World); }
        previous_rotate = movement;
    }
    x++;
}
Easwar Chinraj
  • 436
  • 1
  • 4
  • 10
-1

EventSystem.IspointerOverGameobject is what you need. Event System is UI related so it detects ui element. If you want to ignore UI elements You can use this:

if (!EventSystem.IspointerOverGameobject)
{
    // Your code goes here which only works if pointer not on the UI element
}

If you want to ignore completly and don't need to click that UI object, you should disable raycast on that UI element.

SeLeCtRa
  • 600
  • 1
  • 6
  • 14
  • I've already implemented this and it doesn't work because it cant seem to handle two touches at once – Bob Jan 26 '21 at 15:45