in 소프트웨어 개발

유니티, 모바일 터치 스와이프 토글 구현

유니티 터치 패드 컨트롤에 대해서는 앞에서 다루었다: http://ijemin-web.azurewebsites.net/archives/5698

이는 앞서 말했듯이 한프레임에서 순간 활성(True) 된후 곧바로 비활성(False) 되는 단순 스와이프 토글에는 알맞지 않다. (Axis 값은 버튼이나 FSM의 트리거처럼 동작 하기에는 알맞지 않다.)

단순 스와이프 토글은 싱글톤으로 구현된 SwipeManager와 추상 클래스 SwipeReceiver를 통해 간단히 구현하면 된다.

SwipeManager.cs

(SwipeManager 코드는 https://www.youtube.com/watch?v=poeXGuQ7eUo 를 참조했다.)

using UnityEngine;
using System;


public class SwipeManager : MonoBehaviour
{
	[Flags]
	public enum SwipeDirection
	{
		None = 0, Left = 1, Right = 2, Up = 4, Down = 8
	}

	private static SwipeManager m_instance;

	public static SwipeManager Instance
	{ 
		get
		{
			if (!m_instance)
			{
				m_instance = new GameObject("SwipeManager").AddComponent<SwipeManager>();
			}

			return m_instance;
		}
	}


	public SwipeDirection Direction { get; private set; }

	private Vector3 m_touchPosition;
	private float m_swipeResistanceX = 50.0f;
	private float m_swipeResistanceY = 100f;

	private void Start()
	{
		if (m_instance != this)
		{
			Debug.LogError("Don't instantiate SwipeManager manually");
			DestroyImmediate(this);
		}
	}

	private void Update()
	{


		Direction = SwipeDirection.None;

		if (Input.GetMouseButtonDown(0))
		{
			m_touchPosition = Input.mousePosition;
		}

		if (Input.GetMouseButtonUp(0))
		{
			Vector2 deltaSwipe = m_touchPosition - Input.mousePosition;


			if (Mathf.Abs(deltaSwipe.x) > m_swipeResistanceX)
			{
				// Swipe on the X axis
				Direction |= (deltaSwipe.x < 0) ? SwipeDirection.Right : SwipeDirection.Left;

			}

			if (Mathf.Abs(deltaSwipe.y) > m_swipeResistanceY)
			{
				// Swipe on the Y axis
				Direction |= (deltaSwipe.y < 0) ? SwipeDirection.Up : SwipeDirection.Down;


			}
		}

	}

	public bool IsSwiping(SwipeDirection dir)
	{
		return (Direction & dir) == dir;
	}

}

SwipeReceiver.cs

using System;
using UnityEngine;

public abstract class SwipeReceiver: MonoBehaviour
{
	//override this
	protected virtual void OnSwipeLeft()
	{

	}

	//override this
	protected virtual void OnSwipeRight()
	{

	}

	//override this
	protected virtual void OnSwipeUp()
	{

	}

	//override this
	protected virtual void OnSwipeDonw()
	{

	}

	protected virtual void Update()
	{
		if (SwipeManager.Instance.IsSwiping(SwipeManager.SwipeDirection.Right))
		{
			
			OnSwipeRight();
		}

		if (SwipeManager.Instance.IsSwiping(SwipeManager.SwipeDirection.Left))
		{
			OnSwipeLeft();
		}

		if (SwipeManager.Instance.IsSwiping(SwipeManager.SwipeDirection.Up))
		{
			OnSwipeUp();
		}

		if (SwipeManager.Instance.IsSwiping(SwipeManager.SwipeDirection.Down))
		{
			OnSwipeDonw();
		}
	}


}

이후 스와이프 이벤트를 받아 동작하고 싶은 컴포넌트는 SwipeReceiver 를 상속받아 OnSwipe 계열의 메소드를 오버라이드하면 된다. 토글식으로 동작하기 때문에 스와이프를 하고 손을때지 않는다고 해서 OnSwipe 계열 메소드가 계속 호출되는 불상사는 일어나지 않는다.

 

아래는 클릭이 아닌 화면 스와이프만으로 버튼을 돌아가며 선택하는 코드이다.

using UnityEngine;
using System.Collections;
using UnityEngine.UI;


public class SelectorWithSwipe : SwipeReceiver {

	public Selectable firstSelectedButton;
	// Update is called once per frame

	private Selectable m_currentSelectable;

	private void Start()
	{
		m_currentSelectable = firstSelectedButton;

		m_currentSelectable.Select();
	}

	protected override void OnSwipeUp()
	{
		base.OnSwipeUp();

		var tmp = m_currentSelectable.FindSelectableOnUp();

		m_currentSelectable = tmp ? tmp : m_currentSelectable;

		m_currentSelectable.Select();
	}

	protected override void OnSwipeDonw()
	{
		base.OnSwipeDonw();

		var tmp = m_currentSelectable.FindSelectableOnDown();

		m_currentSelectable = tmp ? tmp : m_currentSelectable;

		m_currentSelectable.Select();
	}

}