简体   繁体   English

检测触摸何时在 UI 元素上

[英]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.我已经尝试跟踪起点和 ID,但是我意识到如果没有检测触摸是否超过跳转按钮的方法,这些都将不起作用。

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

Afaik one issue here is that you are using x the index of the touch. Afaik 这里的一个问题是您正在使用x触摸索引。 IsPointerOverGameObject expects a fingerID as parameter! IsPointerOverGameObject需要一个手指 ID作为参数!

The index x of the touch you use for GetTouch is NOT necessarily equal to the Touch.fingerId !您用于GetTouch的触摸索引x不一定等于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顺便说一句,如果您无论如何都要遍历所有触摸,那么使用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 eg这使您可以立即过滤掉触摸,例如

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这是使用Where基本上等于做

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.一般来说,它仍然让我感到困惑,它应该如何/为什么应该对所有可能的触摸使用相同的共享变量fplp

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.或者通常通过存储第一个有效的touch.fingerId仅使用这些触摸中的一个,然后检查触摸是否仍然是该 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;
        }
    }
}

Check if the EventSystem has any GameObject currently considered as active.检查 EventSystem 是否有任何当前被视为活动的游戏对象。 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++;
}

EventSystem.IspointerOverGameobject is what you need. EventSystem.IspointerOverGameobject是您所需要的。 Event System is UI related so it detects ui element.事件系统与 UI 相关,因此它会检测 ui 元素。 If you want to ignore UI elements You can use this:如果你想忽略 UI 元素你可以使用这个:

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.如果您想完全忽略并且不需要单击该 UI object,则应禁用该 UI 元素上的光线投射。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM