유니티 인풋 시스템을 사용해 모바일에서 주로 사용하는 입력들에 대해 정리한 내용
Value
로, 컨트롤 타입을 Vector2
로 하여 터치의 위치값을 가져오는 액션Button
으로 하는 터치 여부를 가져오는 액션터치 시 TouchPressed
함수가 호출된다.
TouchPressed
함수에서는 터치의 위치값을 가져오는 액션에서 값을 따내 터치한 스크린의 스크린 포지션을 가져온다.
EventSystem.current.IsPointerOverGameObject()
를 이용해 해당 터치가 UI 위의 터치인지 확인할 수 있다.
Value
로, 컨트롤 타입을 Vector2
로 하여 터치의 위치값을 가져오는 액션Pass Through
혹은 Value
, 컨트롤 타입을 Button
으로 하는 터치 여부를 가져오는 액션인풋 시스템 스크립트를 생성해 범용적으로 입력을 할당 및 해제해주는 PlayerInput
클래스와
Swipe 모션만을 집중적으로 파악하는 SwipeDetection
클래스로 나뉘어져 있다.
namespace Player.Input
{
public class PlayerInput : MonoBehaviour
{
internal PlayerInputSystem input;
internal Camera mainCam;
internal PlayerState state;
private StateMachine<PlayerInput> _stateMachine;
#region Events
public delegate void StartTouch(Vector2 pos);
public event StartTouch OnStartTouch;
public delegate void EndTouch(Vector2 pos);
public event StartTouch OnEndTouch;
#endregion
#region Unity Methods
private void Awake()
{
input = new PlayerInputSystem();
mainCam = Camera.main;
state = new PlayerState();
// _stateMachine = new StateMachine<PlayerInput>(this, new OnIdle());
// _stateMachine.AddState(new OnSwipeAndTouch());
// _stateMachine.AddState(new OnPinch());
}
private void OnEnable()
{
input.Enable();
input.Touch.PrimaryTouch.started += StartTouchPrimary;
input.Touch.PrimaryTouch.canceled += EndTouchPrimary;
}
private void OnDisable()
{
input.Touch.PrimaryTouch.started -= StartTouchPrimary;
input.Touch.PrimaryTouch.canceled -= EndTouchPrimary;
input.Disable();
}
private void OnDestroy()
{
// _stateMachine.RemoveAllState();
// _stateMachine = null;
state = null;
mainCam = null;
input = null;
}
private void Update()
{
//_stateMachine.CurrentState.Update();
}
#endregion
#region Input Methods
private void StartTouchPrimary(InputAction.CallbackContext ctx)
{
if (OnStartTouch != null)
{
OnStartTouch(ScreenToWorld(input.Touch.PrimaryPosition.ReadValue<Vector2>()));
}
}
private void EndTouchPrimary(InputAction.CallbackContext ctx)
{
if (OnEndTouch != null)
{
OnEndTouch(ScreenToWorld(input.Touch.PrimaryPosition.ReadValue<Vector2>()));
}
}
#endregion
#region Utilities
private Vector3 ScreenToWorld(Vector3 screenPos)
{
// TODO : change screenPos.z to flexible value
screenPos.z = 5f;
return mainCam.ScreenToWorldPoint(screenPos);
}
public Vector2 PrimaryPosition()
{
return ScreenToWorld(input.Touch.PrimaryPosition.ReadValue<Vector2>());
}
#endregion
}
}
namespace Player.Input
{
public class SwipeDetection : MonoBehaviour
{
private PlayerInput _pInput;
[SerializeField] private float minDistance = 0.2f;
[SerializeField, Range(0f, 1f)] private float dirThreshold = 0.9f;
[SerializeField] private GameObject trail;
private Vector2 _startPos;
private float _startTime;
private Vector2 _endPos;
private float _endTime;
private Coroutine _swipeCor;
#region Input Methods
private void SwipeStart(Vector2 pos)
{
Debug.Log("Start");
_startPos = pos;
trail.SetActive(true);
trail.transform.position = pos;
_swipeCor = StartCoroutine(SwipeCor());
// TODO : Check Second Touch
}
private void SwipeEnd(Vector2 pos)
{
StopCoroutine(_swipeCor);
_swipeCor = null;
trail.SetActive(false);
_endPos = pos;
DetectSwipe();
}
private IEnumerator SwipeCor()
{
while (true)
{
// TODO : Change Camera Position
trail.transform.position = _pInput.PrimaryPosition();
yield return new WaitForEndOfFrame();
}
}
private void DetectSwipe()
{
if (Vector3.Distance(_startPos, _endPos) >= minDistance)
{
// TODO : Swipe Event
Debug.DrawLine(_startPos, _endPos, Color.red, 5f);
Vector2 dir = (_endPos - _startPos).normalized;
SwipeDirection(dir);
}
else
{
// TODO : Touch Event
Debug.Log("Touched");
}
}
private void SwipeDirection(Vector2 direction)
{
if (Vector2.Dot(Vector2.up, direction) > dirThreshold)
{
Debug.Log("Swipe Up");
}
if (Vector2.Dot(Vector2.down, direction) > dirThreshold)
{
Debug.Log("Swipe Down");
}
if (Vector2.Dot(Vector2.left, direction) > dirThreshold)
{
Debug.Log("Swipe Left");
}
if (Vector2.Dot(Vector2.right, direction) > dirThreshold)
{
Debug.Log("Swipe Right");
}
}
#endregion
#region Unity Methods
private void Awake()
{
_pInput = GetComponent<PlayerInput>();
}
private void OnEnable()
{
_pInput.OnStartTouch += SwipeStart;
_pInput.OnEndTouch += SwipeEnd;
}
private void OnDisable()
{
_pInput.OnStartTouch -= SwipeStart;
_pInput.OnEndTouch -= SwipeEnd;
}
private void OnDestroy()
{
_pInput = null;
}
#endregion
}
}
Value
Vector2
에 첫 번째 손가락 터치(Touch #0)의 Position 바인드Value
Vector2
에 두 번째 손가락 터치(Touch #1)의 Position 바인드Button
으로 두 번째 손가락 터치(Touch #1) 확인, 인터랙션에 Press(Press only) 추가using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Player.Input
{
public class PinchDetection : MonoBehaviour
{
[SerializeField] private float camSpeed = 4f;
private PlayerInputSystem _input;
private Coroutine _pinchCor;
private Transform _camTransform;
#region Unity Methods
private void Awake()
{
_input = new PlayerInputSystem();
_camTransform = Camera.main.transform;
}
private void OnEnable()
{
_input.Enable();
}
private void OnDisable()
{
_input.Disable();
}
private void OnDestroy()
{
_input = null;
}
private void Start()
{
_input.Touch.SecondaryTouch.started += _ => PinchStart();
_input.Touch.SecondaryTouch.canceled += _ => PinchEnd();
}
#endregion
#region Input Methods
private void PinchStart()
{
_pinchCor = StartCoroutine(DetectPinch());
}
private void PinchEnd()
{
StopCoroutine(_pinchCor);
}
private IEnumerator DetectPinch()
{
float prevDist = 0f, curDist = 0f;
while (true)
{
curDist = Vector2.Distance(_input.Touch.PrimaryPosition.ReadValue<Vector2>(),
_input.Touch.SecondaryPosition.ReadValue<Vector2>());
// camera zoom in
Vector3 curCamPos = _camTransform.position;
Vector3 targetPos = curCamPos;
if (curDist > prevDist)
{
targetPos.z -= 1;
_camTransform.position = Vector3.Slerp(curCamPos, targetPos, Time.deltaTime * camSpeed);
}
// camera zoom out
else if (curDist < prevDist)
{
targetPos.z += 1;
_camTransform.position = Vector3.Slerp(curCamPos, targetPos, Time.deltaTime * camSpeed);
}
prevDist = curDist;
yield return null;
}
}
#endregion
}
}
잘 읽었습니다. 좋은 정보 감사드립니다.