Как эффективно провести различие между касанием и прокруткой в ​​Unity? - PullRequest
0 голосов
/ 06 июля 2019

Я впервые пытаюсь сделать мобильную игру с сенсорным управлением в Unity. Я в основном получил это работает. Но есть проблема, как вы понимаете, что удар - это не касание?

Как работает мой код, который я частично нашел в обучающих материалах, заключается в том, что для регистрации касания я смотрю, если у пользователя есть сенсорный экран в течение минимального промежутка времени, в данном случае 0,05 секунды. И для просмотра, я смотрю, перемещается ли касание пользователя на минимальное расстояние.

Проблема в том, что довольно часто начало пролистывания регистрируется как касание, поскольку пользователь не двигает пальцем в течение 0,05 секунды. Я мог бы просто сделать минимальное стационарное время, чтобы зарегистрировать нажатие выше, но это означало бы, что в игре будет больше задержки между моментом, когда пользователь касается экрана, и действие будет выполнено ...

Есть ли идеальное решение моей проблемы? В мобильной игре Rayman Adventures тап заставляет игрока прыгать, а смахивание меняет его направление, и оно работает довольно плавно, лишь в очень редких случаях игрок прыгает, когда вы пытаетесь сменить направление. Я понятия не имею, как они это сделали.

Заранее спасибо за ваше время!

Вот мой код:

    public static event Action<SwipeData> OnSwipe = delegate { };
    public static event Action OnTap = delegate { };

    [Header("Swipe parameters")]
    [SerializeField]
    bool m_DetectSwipeOnlyAfterRelease;
    [SerializeField]
    float m_MinDistanceForSwipe;

    [Header("Tap parameters")]
    [SerializeField]
    float m_TapTimeMinThreshold;

    private Vector2 m_FingerDownPosition;
    private Vector2 m_FingerUpPosition;

    private float m_TouchTime;
    private bool m_StationaryTouch;
    private bool m_TapRegistered;
    private bool m_SwipeRegistered;

    void Start() {
        m_TapRegistered = true;
        m_SwipeRegistered = true;
    }

    void Update() {
        if (Input.touchCount == 1) {
            Touch touch = Input.GetTouch(0);
            if (touch.phase == TouchPhase.Began) {
                m_FingerUpPosition = touch.position;
                m_FingerDownPosition = touch.position;
                m_TouchTime = Time.time;
                m_StationaryTouch = true;
                m_TapRegistered = false;
                m_SwipeRegistered = false;
            }

            if(!m_SwipeRegistered && touch.phase == TouchPhase.Moved) {
                m_StationaryTouch = false;
                m_FingerDownPosition = touch.position;
                SwipeDirection swipeDirection = DetectSwipe();
                // If a swipe was registered
                if (!swipeDirection.Equals(SwipeDirection.NONE)) {
                    // And it was horizontal, we reset the swipe detection
                    if (swipeDirection.Equals(SwipeDirection.LEFT) || swipeDirection.Equals(SwipeDirection.RIGHT))
                        m_FingerUpPosition = touch.position;
                    else
                        m_SwipeRegistered = true;
                }
            }

            // If the touch was stationary for the min threshold amount of time we register it as a tap
            if (m_StationaryTouch && !m_TapRegistered && Time.time - m_TouchTime > m_TapTimeMinThreshold) {
                m_TapRegistered = true;
                OnTap();
            }

            if (!m_SwipeRegistered && touch.phase == TouchPhase.Ended && !m_TapRegistered) {
                m_FingerDownPosition = touch.position;
                DetectSwipe();
            }
        }
    }

    private SwipeDirection DetectSwipe() {
        if (SwipeDistanceCheckMet()) {
            SwipeDirection direction;
            if (IsVerticalSwipe()) {
                direction = m_FingerDownPosition.y - m_FingerUpPosition.y > 0 ? SwipeDirection.UP : SwipeDirection.DOWN;
                SendSwipe(direction);
            }
            else {
                direction = m_FingerDownPosition.x - m_FingerUpPosition.x > 0 ? SwipeDirection.RIGHT : SwipeDirection.LEFT;
                SendSwipe(direction);
            }
            m_FingerUpPosition = m_FingerDownPosition;
            return direction;
        }
        return SwipeDirection.NONE;
    }

    private bool IsVerticalSwipe() {
        return VerticalMovementDistance() > HorizontalMovementDistance();
    }

    private bool SwipeDistanceCheckMet() {
        return VerticalMovementDistance() > m_MinDistanceForSwipe || HorizontalMovementDistance() > m_MinDistanceForSwipe;
    }

    private float VerticalMovementDistance() {
        return Mathf.Abs(m_FingerDownPosition.y - m_FingerUpPosition.y);
    }

    private float HorizontalMovementDistance() {
        return Mathf.Abs(m_FingerDownPosition.x - m_FingerUpPosition.x);
    }

    private void SendSwipe(SwipeDirection direction) {
        SwipeData swipeData = new SwipeData()
        {
            Direction = direction,
            StartPosition = m_FingerDownPosition,
            EndPosition = m_FingerUpPosition
        };
        OnSwipe(swipeData);
    }
...