Unity 5 多点触控滑动事件

Unity 5 Multi touch Swipe events

我正在使用 unity 的默认跨平台操纵杆控件的略微修改版本,它在 unity 5.3 中可用,我正在尝试创建一个事件触发器,当我在操纵杆上滑动时(初始点击必须从操纵杆开始)

public class Joystick : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler
{
    public enum AxisOption
    {
        // Options for which axes to use
        Both, // Use both
        OnlyHorizontal, // Only horizontal
        OnlyVertical // Only vertical
    }

    public int MovementRange = 100;
    public AxisOption axesToUse = AxisOption.Both; // The options for the axes that the still will use
    public string horizontalAxisName = "Horizontal"; // The name given to the horizontal axis for the cross platform input
    public string verticalAxisName = "Vertical"; // The name given to the vertical axis for the cross platform input

    Vector3 m_StartPos;
    bool m_UseX; // Toggle for using the x axis
    bool m_UseY; // Toggle for using the Y axis
    CrossPlatformInputManager.VirtualAxis m_HorizontalVirtualAxis; // Reference to the joystick in the cross platform input
    CrossPlatformInputManager.VirtualAxis m_VerticalVirtualAxis; // Reference to the joystick in the cross platform input

    void OnEnable()
    {
        CreateVirtualAxes();
    }

    void Start()
    {
        m_StartPos = transform.position;
    }

    void UpdateVirtualAxes(Vector3 value)
    {
        var delta = m_StartPos - value;
        delta.y = -delta.y;
        delta /= MovementRange;
        if (m_UseX)
        {
            m_HorizontalVirtualAxis.Update(-delta.x);
        }

        if (m_UseY)
        {
            m_VerticalVirtualAxis.Update(delta.y);
        }
    }

    void CreateVirtualAxes()
    {
        // set axes to use
        m_UseX = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyHorizontal);
        m_UseY = (axesToUse == AxisOption.Both || axesToUse == AxisOption.OnlyVertical);

        // create new axes based on axes to use
        if (m_UseX)
        {
            m_HorizontalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(horizontalAxisName);
            CrossPlatformInputManager.RegisterVirtualAxis(m_HorizontalVirtualAxis);
        }
        if (m_UseY)
        {
            m_VerticalVirtualAxis = new CrossPlatformInputManager.VirtualAxis(verticalAxisName);
            CrossPlatformInputManager.RegisterVirtualAxis(m_VerticalVirtualAxis);
        }
    }

    public void OnDrag(PointerEventData data)
    {
        Vector3 newPos = Vector3.zero;

        if (m_UseX)
        {
            int delta = (int)(data.position.x - m_StartPos.x);
            newPos.x = delta;
        }

        if (m_UseY)
        {
            int delta = (int)(data.position.y - m_StartPos.y);
            newPos.y = delta;
        }

        var newPosition = new Vector3(newPos.x, newPos.y, newPos.z);

        transform.position = Vector3.ClampMagnitude(newPosition, MovementRange) + m_StartPos;

        UpdateVirtualAxes(transform.position);
    }

    public void OnPointerUp(PointerEventData data)
    {
        transform.position = m_StartPos;
        UpdateVirtualAxes(m_StartPos);
    }

    public void OnPointerDown(PointerEventData data) { }
}

我已经知道如何创建检测滑动方向的逻辑,我们将定义方法存根,

 public SwipeDirectionEnum GetSwipeDirection(Vector3 startPosition, Vector3 endingPosition);

我遇到的唯一问题是如何通过与操纵杆控件相交或部分相交来滑动末端来在控件外部建立点击?

我写了一个脚本来执行此操作,以防将来有人想这样做。您需要修改 TouchPad.cs 这将使用帧缓存来查找几帧之间的中间方向,这样它就可以适当地支持多点触控。

将此添加到 TouchPad.Cs

  bool isTouchPadCoordinatorInitialized = false;
    TouchPadEventCoordinator touchPadCoordinator;

    public void InitializeTouchPadCoordinator(string horizontalAxis, string verticalAxis, Action swipeUp = null, Action swipeRight = null,
        Action swipeDown = null, Action swipeLeft = null, Action swipeMultiUp = null, 
        Action swipeMultiRight = null, Action swipeMultiDown = null, Action swipeMultiLeft = null)
    {
        touchPadCoordinator = new TouchPadEventCoordinator(horizontalAxis, verticalAxisName, swipeUp, swipeRight, 
                                                            swipeDown, swipeLeft, swipeMultiUp, swipeMultiRight, 
                                                            swipeMultiDown, swipeLeft);
        isTouchPadCoordinatorInitialized = true;
    }

修改on指针向上清除缓存:

    public void OnPointerUp(PointerEventData data)
    {
        m_Dragging = false;
        m_Id = -1;
        UpdateVirtualAxes(Vector3.zero);

        if(isTouchPadCoordinatorInitialized)
        {
            touchPadCoordinator.ClearDirectionCache();
        }

    }

修改更新启动如下:

    void Update()
    {
        if (!m_Dragging)
        {
            return;
        }

        if(isTouchPadCoordinatorInitialized)
        {
            touchPadCoordinator.UpdateSwipe();
        }
   // The rest of the update function goes here

TouchPadCoordinator 文件如下所示:

using UnityEngine;
using System.Collections;
using UnityStandardAssets.CrossPlatformInput;
using System;
using System.Collections.Generic;
using System.Linq;

namespace UnityStandardAssets.CrossPlatformInput
{
    public class TouchPadEventCoordinator : MonoBehaviour
    {

        public int maxFrameCache = 7;

        string _horizontalAxisName;
        string _verticalAxisName;

        List<SwipeDirection> _directionCache = new List<SwipeDirection>();
        Dictionary<SwipeDirection, Action> _directionEventMap = new Dictionary<SwipeDirection, Action>();

        public Action SwipeUp { get; set; }
        public Action SwipeRight { get; set; }
        public Action SwipeDown { get; set; }
        public Action SwipeLeft { get; set; }
        public Action SwipeMultiUp { get; set; }
        public Action SwipeMultiRight { get; set; }
        public Action SwipeMultiDown { get; set; }
        public Action SwipeMultiLeft { get; set; }

        public TouchPadEventCoordinator(string horizontalAxisName, string verticalAxisName, Action swipeUp = null, Action swipeRight = null,
            Action swipeDown = null, Action swipeLeft = null, Action swipeMultiUp = null,
            Action swipeMultiRight = null, Action swipeMultiDown = null, Action swipeMultiLeft = null)
        {
            _horizontalAxisName = horizontalAxisName;
            _verticalAxisName = verticalAxisName;

            SwipeUp = swipeUp;
            SwipeDown = swipeDown;
            SwipeLeft = swipeLeft;
            SwipeRight = swipeRight;
            SwipeMultiUp = swipeMultiUp;
            SwipeMultiDown = swipeMultiDown;
            SwipeMultiLeft = swipeMultiLeft;
            SwipeMultiRight = swipeMultiRight;

            _directionEventMap.Add(SwipeDirection.Up, SwipeUp);
            _directionEventMap.Add(SwipeDirection.Down, SwipeDown);
            _directionEventMap.Add(SwipeDirection.Left, SwipeLeft);
            _directionEventMap.Add(SwipeDirection.Right, SwipeRight);
            _directionEventMap.Add(SwipeDirection.MultiUp, SwipeMultiUp);
            _directionEventMap.Add(SwipeDirection.MultiDown, SwipeMultiDown);
            _directionEventMap.Add(SwipeDirection.MultiLeft, SwipeMultiLeft);
            _directionEventMap.Add(SwipeDirection.MultiRight, SwipeMultiRight);
        }

        public void ProcessSwipeEvent(SwipeDirection swipeDirection)
        {
            if (false == Enum.IsDefined(typeof(SwipeDirection), swipeDirection))
            {
                throw new Exception("Event Not defined");
            }

            _directionCache.Add(swipeDirection);

            if (_directionCache.Count == maxFrameCache)
            {
                var averageSwipeDirection = GetAverageSwipeDirection();
                Action swipeEvent = _directionEventMap[averageSwipeDirection];

                if (null != swipeEvent)
                {
                    swipeEvent();
                }

                ClearDirectionCache();
            }

        }

        public SwipeDirection GetAverageSwipeDirection()
        {
            return _directionCache.GroupBy(x => x)
                     .Select(directionGroup => new
                     {
                         directionGroup.Key,
                         Count = directionGroup.Count()
                     }).OrderByDescending(x => x.Count)
                     .FirstOrDefault().Key;
        }

        public void ClearDirectionCache()
        {
            _directionCache.Clear();
        }

        public enum SwipeDirection
        {
            Up,
            Right,
            Down,
            Left,
            MultiUp,
            MultiRight,
            MultiDown,
            MultiLeft,
        }

        public void UpdateSwipe()
        {
            var horizontal = CrossPlatformInputManager.GetAxis(_horizontalAxisName);
            var vertical = CrossPlatformInputManager.GetAxis(_verticalAxisName);

            //No Touch Occured
            if (vertical == 0 && horizontal == 0)
            {
                return;
            }

            if (Input.touchCount > 1)
            {

            }

            //If they swipe at exactly a 45 register as horizontal so atleast we registered a hit
            if (Mathf.Abs(horizontal) >= Mathf.Abs(vertical))
            {
                HandleHorizontalMovement(horizontal);
            }
            else
            {
                HandleVerticalMovement(vertical);
            }
        }

        protected void HandleVerticalMovement(float vertical)
        {
            if (vertical > 0)
            {
                ProcessSwipeEvent(SwipeDirection.Up);
            }
            else
            {
                ProcessSwipeEvent(SwipeDirection.Down);
            }
        }

        protected void HandleHorizontalMovement(float horizontal)
        {
            if (horizontal > 0)
            {
                ProcessSwipeEvent(SwipeDirection.Right);
            }
            else
            {
                ProcessSwipeEvent(SwipeDirection.Left);
            }
        }

        protected void HandleDepthMovement(float horizontal, float vertical)
        {
            //establish the most prodiment direction
            if (Mathf.Abs(horizontal) >= Mathf.Abs(vertical))
            {
                if (horizontal > 0)
                {
                    ProcessSwipeEvent(SwipeDirection.MultiRight);
                }
                else if (horizontal < 0)
                {
                    ProcessSwipeEvent(SwipeDirection.MultiLeft);
                }
            }
            else
            {
                if (vertical > 0)
                {
                    ProcessSwipeEvent(SwipeDirection.MultiUp);
                }
                else if (vertical < 0)
                {
                    ProcessSwipeEvent(SwipeDirection.MultiDown);
                }
            }
        }
    }
}

使用它看起来像这样:

    var touchPad = transform.parent.Find(TOUCH_PAD_PATH);
    _touchPad = touchPad.GetComponent<TouchPad>();

    _touchPad.InitializeTouchPadCoordinator(GameHelper.InputAxisName.TouchHorizontal.ToString(), GameHelper.InputAxisName.TouchHorizontal.ToString(),
                                             SwipeUpEvent, SwipeRightEvent, SwipeDownEvent, SwipeLeftEvent);

就像注释一样,SwipeEvent 是调用滑动时将执行的操作。

请注意,由于我尚未移植到移动设备,因此尚未通过多次滑动事件进行测试,因此使用风险自负。我会在手机上测试我的游戏后更新这个