简体   繁体   English

Unity3d 如何检测 android 上的点击?

[英]Unity3d How to detect taps on android?

Currently I am struggling to work out how to create a simple bit of code that will tell me if a tap has happened, allowing me to get the position of taps.目前我正在努力解决如何创建一个简单的代码来告诉我是否发生了点击,让我获得点击的位置。 Having looked through many different articles I am rather stumped as Touch.tapCount that is often suggested only works for ios.浏览了许多不同的文章后,我很Touch.tapCount ,因为Touch.tapCount经常被建议只适用于 ios。 Also, i have tried to use Touch.deltaTime and/or Touch.deltaPosition to detect a tap but have failed.此外,我尝试使用Touch.deltaTime和/或Touch.deltaPosition来检测点击但失败了。

I define a tap as having我将水龙头定义为

  • A very short period between the finger initially touching and finally exiting the phone手指最初接触手机和最终退出手机之间的时间很短

  • Little or no movement很少或没有运动

Thanks for reading this, I hope its clear and precise and if any detail or assistance is required on my behalf in order for your to answer feel free to ask.感谢您阅读本文,我希望它清晰准确,如果需要代表我的任何细节或帮助以便您回答,请随时提问。 Any assistance is gratefully received.任何帮助表示感谢。 Thanks.谢谢。

Note - I work in C#注意 - 我在 C# 中工作

First you have to find out if your Android device indeed can register several touches.首先,您必须确定您的 Android 设备是否确实可以注册多次触摸。 If you have a newer device, this shouldn't be a problem.如果您有较新的设备,这应该不是问题。 I'm going to assume that your device can, and if it can not - you'll soon find out soon enough.我将假设您的设备可以,如果不能 - 您很快就会发现。

let's start with the update method.让我们从更新方法开始。

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

What we first want to do is register touches.我们首先要做的是注册触摸。 We can do this by putting a foreach inside, checking for touches in Input.touches.我们可以通过在里面放置一个 foreach 来做到这一点,检查 Input.touches 中的触摸。 Like this:像这样:

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

    }
}

By doing this, we are always checking how many touches there are currently on the screen.通过这样做,我们一直在检查屏幕上当前有多少触摸。 What we can now do is check by fingerId, and if fingerId == 0, 1, 2... run some code.我们现在可以做的是检查fingerId,如果fingerId == 0, 1, 2 ... 运行一些代码。 Here's what we got now:这是我们现在得到的:

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

We're great so far!到目前为止我们很棒! What we now want to do is detect the motion we want.我们现在要做的是检测我们想要的运动。 In our case, we wanted taps, right?在我们的例子中,我们想要水龙头,对吧? That should work perfectly with TouchPhase Began, and Ended.这应该与 TouchPhase Began 和 Ended 完美配合。 There's also TouchPhase.Moved, but we don't need that now.还有 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.");
    }
}

Here we are checking the phase of the corresponding finger.在这里,我们正在检查相应手指的相位。 If you run that now, you should be able to see the messages in the console whenever your first touch enters, as well as leaves the screen.如果你现在运行它,你应该能够在你第一次触摸进入和离开屏幕时看到控制台中的消息。 This can be done with several touches, so here's the 'whole' script:这可以通过几次触摸来完成,所以这里是“整个”脚本:

    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.");
            }
        }
    }
}

I'm hoping this will help you.我希望这会帮助你。 I'm fairly new at this myself, so if we're lucky - someone with more experience can come and help.我自己对这方面还很陌生,所以如果我们幸运的话 - 有更多经验的人可以来帮忙。 I'm confident that this could be written a lot cleaner.我相信这可以写得更清晰。 Just remember that if you build it, you can't see the console messages.请记住,如果您构建它,您将看不到控制台消息。 Check out Unity Remote if you haven't already.如果您还没有,请查看 Unity Remote。 Good luck!祝你好运! :) :)

After doing some searching (Googling "unity mobile detect tap"), I found this as the top search result.做了一些搜索(谷歌搜索“unity mobile detection tap”)后,我发现这是最热门的搜索结果。 @Mothil's answer gets us very close to the solution and OP's answer solves the question. @Mothil 的回答让我们非常接近解决方案,而 OP 的回答解决了这个问题。 However, OP's answer does not account for multiple taps.但是,OP 的答案并未考虑多次点击。 Also tracking the count of started touches, ended touches, and moved touches (eg int SCount, MCount, ECount ) is not necessary.也不需要跟踪开始的触摸、结束的触摸和移动的触摸(例如int SCount, MCount, ECount )的int SCount, MCount, ECount

Instead we can directly loop through each touch and track each individual touch by its fingerId as @mothil did.相反,我们可以像@mothil 那样直接遍历每个触摸并通过其fingerId 跟踪每个单独的触摸。 For this we'll need two arrays to track a tap's characteristics: 1) short time delay, and 2) no movement.为此,我们需要两个数组来跟踪水龙头的特性:1) 短时间延迟,以及 2) 无移动。 In the arrays below, the array index is the fingerId.在下面的数组中,数组索引是fingerId。

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

We'll also need one more variable to store our desired tap time threshold.我们还需要一个变量来存储我们想要的点击时间阈值。 In my tests, I found that a threshold of 0.2f works pretty well.在我的测试中,我发现0.2f的阈值效果很好。

private float tapTimeThreshold = 0.2f;

In the Start() function, we'll initialize this to hold 10 elements for 10 touches.Start()函数中,我们将初始化它以保存 10 个元素以进行 10 次触摸。 This can be modified to however many touches desired.这可以修改为所需的许多触摸。

In the Update() function, we loop through each touch.Update()函数中,我们遍历每次触摸。 If in TouchPhase.Began then we set the timeTouchBegan[fingerIndex] to the current time;如果在TouchPhase.Began那么我们将timeTouchBegan[fingerIndex]设置为当前时间; we also set touchDidMove[fingerIndex] to false.我们还将touchDidMove[fingerIndex]设置为 false。

If in TouchPhase.Moved , we set touchDidMove[fingerIndex] to true.如果在TouchPhase.Moved ,我们将touchDidMove[fingerIndex]设置为 true。

Finally, in TouchPhase.Ended , we can calculate the tap time.最后,在TouchPhase.Ended ,我们可以计算点击时间。

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

If the tap time is less than the threshold and the touch did not move then we have a verified tap.如果点击时间小于阈值并且触摸没有移动,那么我们有一个经过验证的点击。

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

Complete Script完整脚本

Here's the full 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 Tests统一测试

I tested this in my game using Unity Remote.我使用 Unity Remote 在我的游戏中对此进行了测试。 In the screenshot below, you can see my debug console logs.在下面的屏幕截图中,您可以看到我的调试控制台日志。 I did a four finger tap.我做了四指敲击。 You can see that fingers 0 through 3 entered and left without any movement detected.您可以看到手指 0 到 3 进入和离开时没有检测到任何移动。 A tap was detected for each finger and each tap's location was printed to the console.检测到每个手指的轻敲,并将每个轻敲的位置打印到控制台。

在此处输入图片说明

I am pretty sure that tapCount will work on Android.我很确定tapCount 可以在Android 上运行。 In my scenario, what handles input is not deriving from a MonoBehaviour.在我的场景中,处理输入的不是从 MonoBehaviour 派生的。 Instead its just an object I pass around.相反,它只是我传递的一个对象。 I wont supply the full class, but just what handles 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)
                    {
                    }
                }

The i is because I want to know how many touches the user has, but this should get you going at least. i 是因为我想知道用户有多少触摸,但这至少应该让你继续前进。

Edit: I forgot to mention, you might want this if statement chunk inside a coroutine.编辑:我忘了提到,您可能需要在协程中使用 if 语句块。

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

Hope this helps.希望这会有所帮助。

Thank you for everyone response's and I am grateful and I am sure there are several different ways to detect a tap. 感谢大家的回复,我很感激,我确信有几种不同的方法来检测水龙头。 Below is my code, which having been prompted about phases, uses phases to tell if a touch has a movement phase or not allowing me to tell if a touch has moved, fulfilling the tap characteristic of : 下面是我的代码,它已被提示有关阶段,使用阶段来判断触摸是否有运动阶段或不允许我判断触摸是否已移动,实现以下的分接特性:

Little or no movement 很少或没有运动

Also by looking at the time elapsed between the touch began and ended phase i can detect the second characteristic for a tap, which is : 另外,通过查看触摸开始和结束阶段之间经过的时间,我可以检测到敲击的第二个特征,即:

A very short period between the finger initially touching and finally exiting the phone 手指最初触摸并最终退出手机之间的时间非常短

Here is my code below - 这是我的代码 -

using UnityEngine;
using System.Collections;

public class TouchManager : MonoBehaviour
{
    public Vector2 touchPos;
    int SCount; // Count of started touches
    int MCount; // Count of ended touches
    int ECount; // Count of moved touches
    int LastPhaseHappend; // 1 = S, 2 = M, 3 = E
    float TouchTime; // Time elapsed between touch beginning and ending
    float StartTouchTime; // Time.realtimeSinceStartup at start of touch
    float EndTouchTime; // Time.realtimeSinceStartup at end of touch

    void Start()
    {
        SCount = 0;
        MCount = 0;
        ECount = 0;
        StartTouchTime = 0;
        EndTouchTime = 0;
        TouchTime = 0;
        // All variables are intialized at zero, likely uneccessary as i believe they're 'zeroed' by default
    }

    // Update is called once per frame
    void Update()
    {
        touchPos = Vector3.zero;
        if (Input.touchCount != 0)
        {
            Touch currentTouch = Input.GetTouch(0);
            switch (currentTouch.phase)
            {
                case TouchPhase.Began:
                    if (LastPhaseHappend != 1)
                    {
                        SCount++;
                        StartTouchTime = Time.realtimeSinceStartup;
                    }
                    LastPhaseHappend = 1;
                    break;

                case TouchPhase.Moved:
                    if (LastPhaseHappend != 2)
                    {
                        MCount++;
                    }
                    LastPhaseHappend = 2;
                    break;

                case TouchPhase.Ended:
                    if (LastPhaseHappend != 3)
                    {
                        ECount++;
                        EndTouchTime = Time.realtimeSinceStartup;
                        TouchTime = EndTouchTime - StartTouchTime;
                    }
                    LastPhaseHappend = 3;
                    break;
            }
            if (SCount == ECount && ECount != MCount && TouchTime < 1)
                // TouchTime for a tap can be further defined
            {
                //Tap has happened;
                touchPos = currentTouch.position;
                MCount++;
            }
        }
    }
}

simple yet effective, jsut add the engine at top UI and add code in update dune简单而有效,只需在顶部 UI 中添加引擎并在更新沙丘中添加代码

enter image description here在此处输入图片说明

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

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