简体   繁体   中英

Unity 5 Multi touch Swipe events

I'm using a slightly modified version of unity's default Cross platform joystick control, which is available in unity 5.3, I'm trying to create an event trigger to which would fire when I swipe across the joystick (initial click must start off of joystick)

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) { }
}

I already know how to create the logic to detect the direction of the swipe, we will define the method stub as this,

 public SwipeDirectionEnum GetSwipeDirection(Vector3 startPosition, Vector3 endingPosition);

The only part I'm having trouble with is how can I establish the click outside of the control, with a swipe the ends by intersecting or partially intersecting the joystick control?

I wrote a script to do this in case anyone is looking to do this in the future. You will need to modify the TouchPad.cs this will use a framecache to find the median direction between a few frames, that way it can support multitouch appropiately.

Add this to the 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;
    }

Modify the on Pointer up to clear the cache:

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

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

    }

Modify the update to start like this:

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

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

The TouchPadCoordinator file looks like this:

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

And to use it would look like this:

    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);

Just as a note SwipeEvent are actions that will be executed when that swipe is called.

Just as a note this has not been tested with multiple swipe events since I have not ported to mobile yet so use at your own risk. I'll update this after I test my game on mobile

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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