簡體   English   中英

檢測觸摸何時在 UI 元素上

[英]Detecting when a touch is over a UI element

我正在創建一個觸摸控制游戲,它會在您觸摸和拖動時旋轉平台,但是我無法讓它忽略對跳轉按鈕的觸摸,導致它認為您已經非常快速地將同一根手指移動到它上面作為一次長滑動. 我已經嘗試跟蹤起點和 ID,但是我意識到如果沒有檢測觸摸是否超過跳轉按鈕的方法,這些都將不起作用。

我檢測觸摸的代碼:

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 這里的一個問題是您正在使用x觸摸索引。 IsPointerOverGameObject需要一個手指 ID作為參數!

您用於GetTouch的觸摸索引x不一定等於Touch.fingerId

應該是

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

順便說一句,如果您無論如何都要遍歷所有觸摸,那么使用Input.touches會更容易

返回表示最后一幀期間所有觸摸狀態的對象列表。 (只讀)(分配臨時變量)。

var touches = Input.touches;

這使您可以立即過濾掉觸摸,例如

using System.Linq;

...


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

這是使用Where基本上等於做

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

    ...
}

一般來說,它仍然讓我感到困惑,它應該如何/為什么應該對所有可能的觸摸使用相同的共享變量fplp

您可能更應該使用

var moved = touch.deltaPosition;

而是使用該值。

或者通常通過存儲第一個有效的touch.fingerId僅使用這些觸摸中的一個,然后檢查觸摸是否仍然是該 ID。 同時忽略所有其他觸摸。

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

檢查 EventSystem 是否有任何當前被視為活動的游戲對象。 如果是,則在按鈕上執行觸摸,否則觸摸不在按鈕上。

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是您所需要的。 事件系統與 UI 相關,因此它會檢測 ui 元素。 如果你想忽略 UI 元素你可以使用這個:

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

如果您想完全忽略並且不需要單擊該 UI object,則應禁用該 UI 元素上的光線投射。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM