Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
122 views
in Technique[技术] by (71.8m points)

c# - Detecting when a touch is over a UI element

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++;
        }
question from:https://stackoverflow.com/questions/65903947/detecting-when-a-touch-is-over-a-ui-element

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...