Unity3d 如何检测 android 上的点击?

Unity3d How to detect taps on android?

目前我正在努力研究如何创建一段简单的代码来告诉我是否发生了点击,让我能够获得点击的位置。浏览了许多不同的文章后,我感到很困惑,因为 Touch.tapCount 通常被建议只适用于 ios。此外,我曾尝试使用 Touch.deltaTime and/or Touch.deltaPosition 来检测点击但失败了。

我将水龙头定义为具有

感谢您阅读本文,我希望它清晰准确,如果您需要任何细节或帮助以便您回答,请随时询问。非常感谢收到任何帮助。谢谢

注意 - 我在 C# 中工作

我很确定 tapCount 会在 Android 上运行。 在我的场景中,处理输入的不是从 MonoBehaviour 派生的。相反,它只是我传递的一个对象。我不会提供完整的 class,但只是处理 phone touches/taps.

if (Input.touchCount > i)
                {
                    if (Input.GetTouch(i).phase == TouchPhase.Began)
                    {
                    }
                    if (Input.GetTouch(i).phase == TouchPhase.Canceled)
                    {
                    }
                    if (Input.GetTouch(i).phase == TouchPhase.Ended)
                    {
                    }
                    if (Input.GetTouch(i).phase == TouchPhase.Moved)
                    {
                    }
                    if (Input.GetTouch(i).phase == TouchPhase.Stationary)
                    {
                    }
                }

i 是因为我想知道用户有多少次触摸,但这至少应该让你继续。

编辑:我忘了说,你可能希望这个 if 语句块在协程中。

https://docs.unity3d.com/Manual/Coroutines.html

希望对您有所帮助。

首先,您必须确定您的 Android 设备是否确实可以注册多次触摸。如果您有较新的设备,这应该不是问题。我假设您的设备可以,如果不能 - 您很快就会发现。

让我们从更新方法开始。

void Update() {
// Nothing at the moment
}

我们首先要做的是注册触摸。我们可以通过在内部放置一个 foreach,检查 Input.touches 中的触摸来做到这一点。像这样:

    void Update() {
    foreach (Touch touch in Input.touches) {

    }
}

通过这样做,我们总是在检查屏幕上当前有多少触摸。我们现在可以做的是检查 fingerId,如果 fingerId == 0, 1, 2... 运行 一些代码。这是我们现在得到的:

    void Update() {
        foreach (Touch touch in Input.touches) {

        if (touch.fingerId == 0) {
            // Finger 1 is touching! (remember, we count from 0)
        }

        if (touch.fingerId == 1) {
            // finger 2 is touching! Huzzah!
        }
    }
}

到目前为止我们都很棒!我们现在要做的是检测我们想要的运动。在我们的例子中,我们想要水龙头,对吧?这应该与 TouchPhase Began, and Ended 完美配合。还有 TouchPhase.Moved,但我们现在不需要了。

if (touch.fingerId == 0) {

    if (Input.GetTouch(0).phase == TouchPhase.Began) {
        Debug.Log("First finger entered!");
    }

    if (Input.GetTouch(0).phase == TouchPhase.Ended) {
        Debug.Log("First finger left.");
    }
}

这里我们检查的是对应手指的相位。如果您 运行 现在,您应该能够在第一次触摸进入和离开屏幕时在控制台中看到消息。这可以通过几次触摸来完成,所以这里是 'whole' 脚本:

    void Update() {
    foreach (Touch touch in Input.touches) {

        if (touch.fingerId == 0) {
            if (Input.GetTouch(0).phase == TouchPhase.Began) {
                Debug.Log("First finger entered!");
            }
            if (Input.GetTouch(0).phase == TouchPhase.Ended) {
                Debug.Log("First finger left.");
            }
        }

        if (touch.fingerId == 1) {
            if (Input.GetTouch(1).phase == TouchPhase.Began) {
                Debug.Log("Second finger entered!");
            }
            if (Input.GetTouch(1).phase == TouchPhase.Ended) {
                Debug.Log("Second finger left.");
            }
        }
    }
}

希望对您有所帮助。我自己在这方面还很陌生,所以如果我们幸运的话——有更多经验的人可以来帮忙。我相信这可以写得更干净。请记住,如果您构建它,您将看不到控制台消息。如果您还没有,请查看 Unity Remote。祝你好运! :)

经过一些搜索(谷歌搜索 "unity mobile detect tap"),我发现这是最重要的搜索结果。 @Mothil 的回答让我们非常接近解决方案,而 OP 的回答解决了问题。但是,OP 的答案并未考虑多次点击。也不需要跟踪开始触摸、结束触摸和移动触摸(例如 int SCount, MCount, ECount)的计数。

相反,我们可以像@mothil 那样直接遍历每个触摸并通过其 fingerId 跟踪每个单独的触摸。为此,我们需要两个阵列来跟踪水龙头的特性:1) 短时间延迟,以及 2) 没有移动。在下面的数组中,数组索引是 fingerId。

private float[] timeTouchBegan;
private bool[] touchDidMove;

我们还需要一个变量来存储我们想要的点击时间阈值。在我的测试中,我发现 0.2f 的阈值效果很好。

private float tapTimeThreshold = 0.2f;

Start() 函数中,我们将初始化它以容纳 10 个元素进行 10 次触摸。这可以根据需要进行修改。

Update()函数中,我们遍历每个触摸。如果在 TouchPhase.Began 中,那么我们将 timeTouchBegan[fingerIndex] 设置为当前时间;我们还将 touchDidMove[fingerIndex] 设置为 false。

如果在 TouchPhase.Moved 中,我们将 touchDidMove[fingerIndex] 设置为 true。

最后,在TouchPhase.Ended中,我们可以计算点击时间

float tapTime = Time.time - timeTouchBegan[fingerIndex];

如果点击时间小于阈值并且触摸没有移动,那么我们有一个经过验证的点击。

if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
{
    // Tap detected at touch.position
}

完成脚本

这是完整的class:

public class TapManager : MonoBehaviour
{        
    private float[] timeTouchBegan;
    private bool[] touchDidMove;
    private float tapTimeThreshold = 0.2f;

    void Start()
    {
        timeTouchBegan = new float[10];
        touchDidMove = new bool[10];
    }

    private void Update()
    {
        // Touches
        foreach (Touch touch in Input.touches)
        {
            int fingerIndex = touch.fingerId;

            if (touch.phase == TouchPhase.Began)
            {
                Debug.Log("Finger #" + fingerIndex.ToString() + " entered!");
                timeTouchBegan[fingerIndex] = Time.time;
                touchDidMove[fingerIndex] = false;
            }
            if (touch.phase == TouchPhase.Moved)
            {
                Debug.Log("Finger #" + fingerIndex.ToString() + " moved!");
                touchDidMove[fingerIndex] = true;
            }
            if (touch.phase == TouchPhase.Ended)
            {
                float tapTime = Time.time - timeTouchBegan[fingerIndex];
                Debug.Log("Finger #" + fingerIndex.ToString() + " left. Tap time: " + tapTime.ToString());
                if (tapTime <= tapTimeThreshold && touchDidMove[fingerIndex] == false)
                {
                    Debug.Log("Finger #" + fingerIndex.ToString() + " TAP DETECTED at: " + touch.position.ToString());
                }
            }            
        }
    }   
}

统一测试

我在游戏中使用 Unity Remote 对此进行了测试。在下面的屏幕截图中,您可以看到我的调试控制台日志。我做了一个四指轻敲。您可以看到手指 0 到 3 进入和离开时没有检测到任何移动。每根手指都检测到一次敲击,每次敲击的位置都打印到控制台。

简单而有效,只需在顶部添加引擎 UI 并在更新沙丘中添加代码

enter image description here