检测滑动手势方向

Posted

技术标签:

【中文标题】检测滑动手势方向【英文标题】:Detect swipe gesture direction 【发布时间】:2017-10-18 08:22:51 【问题描述】:

这是我尝试模拟滑动手势的代码,因此当我构建到移动设备时,我知道它会起作用。没有任何记录,我对为什么它似乎不起作用感到困惑。我希望它在控制台中打印出来,我要么刷了RTL(从右到左)或LTR(从左到右)。我看不出我做错了什么。

void Update()

    if (Input.GetMouseButtonDown(0))
    
        startPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    
    if (Input.GetMouseButtonUp(0))
    
        endPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
    

    if (startPosition != endPosition && startPosition != Vector3.zero && endPosition != Vector3.zero)
    
        float deltaX = endPosition.x - startPosition.x;
        float deltaY = endPosition.y - startPosition.y;
        if ((deltaX > 5.0f || deltaX < -5.0f) && (deltaY >= -1.0f || deltaY <= 1.0f))
        
            if (startPosition.x < endPosition.x)
            
                print("LTR");
            
            else
            
                print("RTL");
            
        
        startPosition = endPosition = Vector3.zero;
    

【问题讨论】:

你有太多的检查,特别是最后一个 (endPosition != zero ) 不可能是真的。改用标志 drag = true 和 drag = false 【参考方案1】:

我可以在您的代码中发现一些问题。将Vector3==!= 进行比较并不是一个好主意。近似比较就好了。您在移动平台上使用Input.GetMouseButtonDown

您需要使用Input.touches 来执行此操作。循环遍历它,将开始位置存储在TouchPhase.Began 中,然后将结束位置存储在TouchPhase.Ended 中。然后,您可以使用这两个变量来确定手指的方向。

TouchPhase.Moved 的帮助下,即使手指尚未释放,下面的代码也会检测滑动方向。您可以通过启用 detectSwipeOnlyAfterRelease 布尔变量来禁用它。你也可以修改SWIPE_THRESHOLD的敏感度。

public class SwipeDetector : MonoBehaviour

    private Vector2 fingerDown;
    private Vector2 fingerUp;
    public bool detectSwipeOnlyAfterRelease = false;

    public float SWIPE_THRESHOLD = 20f;

    // Update is called once per frame
    void Update()
    

        foreach (Touch touch in Input.touches)
        
            if (touch.phase == TouchPhase.Began)
            
                fingerUp = touch.position;
                fingerDown = touch.position;
            

            //Detects Swipe while finger is still moving
            if (touch.phase == TouchPhase.Moved)
            
                if (!detectSwipeOnlyAfterRelease)
                
                    fingerDown = touch.position;
                    checkSwipe();
                
            

            //Detects swipe after finger is released
            if (touch.phase == TouchPhase.Ended)
            
                fingerDown = touch.position;
                checkSwipe();
            
        
    

    void checkSwipe()
    
        //Check if Vertical swipe
        if (verticalMove() > SWIPE_THRESHOLD && verticalMove() > horizontalValMove())
        
            //Debug.Log("Vertical");
            if (fingerDown.y - fingerUp.y > 0)//up swipe
            
                OnSwipeUp();
            
            else if (fingerDown.y - fingerUp.y < 0)//Down swipe
            
                OnSwipeDown();
            
            fingerUp = fingerDown;
        

        //Check if Horizontal swipe
        else if (horizontalValMove() > SWIPE_THRESHOLD && horizontalValMove() > verticalMove())
        
            //Debug.Log("Horizontal");
            if (fingerDown.x - fingerUp.x > 0)//Right swipe
            
                OnSwipeRight();
            
            else if (fingerDown.x - fingerUp.x < 0)//Left swipe
            
                OnSwipeLeft();
            
            fingerUp = fingerDown;
        

        //No Movement at-all
        else
        
            //Debug.Log("No Swipe!");
        
    

    float verticalMove()
    
        return Mathf.Abs(fingerDown.y - fingerUp.y);
    

    float horizontalValMove()
    
        return Mathf.Abs(fingerDown.x - fingerUp.x);
    

    //////////////////////////////////CALLBACK FUNCTIONS/////////////////////////////
    void OnSwipeUp()
    
        Debug.Log("Swipe UP");
    

    void OnSwipeDown()
    
        Debug.Log("Swipe Down");
    

    void OnSwipeLeft()
    
        Debug.Log("Swipe Left");
    

    void OnSwipeRight()
    
        Debug.Log("Swipe Right");
    

【讨论】:

我知道在移动设备上我必须将其更改为 Input.touches,我只是想在我的计算机上模拟它,因为 unity 不会在计算机上读取 Input.touches。只有在构建在移动设备上之后才会这样做。谢谢你虽然帮了很多忙。 倒数第二句话不是真的。您可以在编辑器中将手机连接到计算机进行测试,而无需构建它。请参阅this 并节省您的时间。不客气!【参考方案2】:

感谢程序员,我使用了他的建议并编写了一个小组件,它可以与鼠标和触摸一起使用。鼠标将允许您在 PC 上调试应用程序。我还添加了以秒为单位的时间阈值,因为滑动不能太长。

using System;
using UnityEngine;
using UnityEngine.Events;

public class SwipeManager : MonoBehaviour 

  public float swipeThreshold = 50f;
  public float timeThreshold = 0.3f;

  public UnityEvent OnSwipeLeft;
  public UnityEvent OnSwipeRight;
  public UnityEvent OnSwipeUp;
  public UnityEvent OnSwipeDown;

  private Vector2 fingerDown;
  private DateTime fingerDownTime;
  private Vector2 fingerUp;
  private DateTime fingerUpTime;

  private void Update () 
    if (Input.GetMouseButtonDown(0)) 
      this.fingerDown = Input.mousePosition;
      this.fingerUp = Input.mousePosition;
      this.fingerDownTime = DateTime.Now;
    
    if (Input.GetMouseButtonUp(0)) 
      this.fingerDown = Input.mousePosition;
      this.fingerUpTime = DateTime.Now;
      this.CheckSwipe();
    
    foreach (Touch touch in Input.touches) 
      if (touch.phase == TouchPhase.Began) 
        this.fingerDown = touch.position;
        this.fingerUp = touch.position;
        this.fingerDownTime = DateTime.Now;
      
      if (touch.phase == TouchPhase.Ended) 
        this.fingerDown = touch.position;
        this.fingerUpTime = DateTime.Now;
        this.CheckSwipe();
      
    
  

  private void CheckSwipe() 
    float duration = (float)this.fingerUpTime.Subtract(this.fingerDownTime).TotalSeconds;
    if (duration > this.timeThreshold) return;

    float deltaX = this.fingerDown.x - this.fingerUp.x;
    if (Mathf.Abs(deltaX) > this.swipeThreshold) 
      if (deltaX > 0) 
        this.OnSwipeRight.Invoke();
        //Debug.Log("right");
       else if (deltaX < 0) 
        this.OnSwipeLeft.Invoke();
        //Debug.Log("left");
      
    

    float deltaY = fingerDown.y - fingerUp.y;
    if (Mathf.Abs(deltaY) > this.swipeThreshold) 
      if (deltaY > 0) 
        this.OnSwipeUp.Invoke();
        //Debug.Log("up");
       else if (deltaY < 0) 
        this.OnSwipeDown.Invoke();
        //Debug.Log("down");
      
    

    this.fingerUp = this.fingerDown;
  

【讨论】:

【参考方案3】:

为更精确的控制器(和更少的代码!=D)修改了开发者的方法:

using System;
using UnityEngine;
using UnityEngine.Events;
using Utilities;

public class SwipeManager : MonoBehaviour 

  public float swipeThreshold = 40f;
  public float timeThreshold = 0.3f;

  public UnityEvent onSwipeLeft;
  public UnityEvent onSwipeRight;
  public UnityEvent onSwipeUp;
  public UnityEvent onSwipeDown;

  private Vector2 _fingerDown;
  private DateTime _fingerDownTime;
  private Vector2 _fingerUp;
  private DateTime _fingerUpTime;

  private void Update () 
    if (Input.GetMouseButtonDown(0)) 
      _fingerDown = Input.mousePosition;
      _fingerUp = Input.mousePosition;
      _fingerDownTime = DateTime.Now;
    

    if (Input.GetMouseButtonUp(0)) 
      _fingerDown = Input.mousePosition;
      _fingerUpTime = DateTime.Now;
      CheckSwipe();
    

    foreach (var touch in Input.touches) 
      if (touch.phase == TouchPhase.Began) 
        _fingerDown = touch.position;
        _fingerUp = touch.position;
        _fingerDownTime = DateTime.Now;
      

      if (touch.phase == TouchPhase.Ended) 
        _fingerDown = touch.position;
        _fingerUpTime = DateTime.Now;
        CheckSwipe();
      
    
  

  private void CheckSwipe() 
    var duration = (float)_fingerUpTime.Subtract(_fingerDownTime).TotalSeconds;
    var dirVector = _fingerUp - _fingerDown;

    if (duration > timeThreshold) return;
    if (dirVector.magnitude < swipeThreshold) return;

    var direction = dirVector.Rotation(180f).Round();

    print(direction);

    if (direction >= 45 && direction < 135) onSwipeUp.Invoke();
    else if (direction >= 135 && direction < 225) onSwipeRight.Invoke();
    else if (direction >= 225 && direction < 315) onSwipeDown.Invoke();
    else if (direction >= 315 && direction < 360 || direction >= 0 && direction < 45) onSwipeLeft.Invoke();
  

【讨论】:

很久以前,但现在才看到这个错误...?dirVector.Rotation(180f).Round() 我的意思是获取向量的角度(典型的笛卡尔格式:XY)并将其旋转 180 度...【参考方案4】:

我搜索了同样的东西,发现创建资产以方便滑动检测并与社区分享是合理的。所以这里是github。我的解决方案支持不同的用例,包括:8 方向滑动检测、4 方向、2 方向(左右或上下)、六边形网格上的滑动。所有列出的都包含为预设,但您也可以将其配置为检测任意数量的 Vector3 方向。所以 ti 真的很灵活。此外,您可以尝试WebGL build 或查看video tutorial。如果您尝试一下,请告诉我(通过 youtube 评论,或查看 github 上的联系人部分),它是否适合您的情况,是否足够舒适。

【讨论】:

【参考方案5】:
Try this Out.  
I hope this helps.




void Update()
if (Input.GetMouseButtonDown(0))
    startPosition = Input.mousePosition;

if (Input.GetMouseButtonUp(0))
    float swipe = startPosition.x - Input.mousePosition.x;



        if (swipe < 0)
        
            print("LTR");
         else
            print("RTL");
        
    



【讨论】:

以上是关于检测滑动手势方向的主要内容,如果未能解决你的问题,请参考以下文章

移动应用滑动屏幕方向判断解决方案,JS判断手势方向

android 判断左右滑动,上下滑动的GestureDetector简单手势检测

使用手势的 iOS Phonegap 滑动检测

检测在手势识别器对象区域之外开始的滑动

滑动手势识别器在垂直方向上不起作用

检测滑动手势 iOS - Cordova/Phonegap Javascript