상태 패턴을 적용한 유니티 인풋 시스템

정선호·2023년 8월 5일
0

Original

목록 보기
2/5

유니티 인풋 시스템


개요

인풋 시스템 작동 원리

유니티의 새 인풋 시스템은 대리자 기반의 이벤트 시스템으로 구현되어 있다.

간단하고 빠른 구현을 위해 같은 오브젝트에 소속된 컴포넌트들에게 메시지 전달을 하거나 UnityEvent를 이용하는 방식도 있지만, 가장 방대하고 자유로운 입력 시스템 사용 방식은 인풋 시스템의 C# 스크립트를 생성한 후 해당 스크립트의 이벤트에 함수를 구독시키는 것이다.

즉 스크립트 상으로 특정 입력 액션에 개발자가 원하는 액션을 구독시키면 플레이어가 특정 입력을 입력할 시 구독된 액션이 실행되게 된다.

이와 비슷하게 스크립트를 이용해서 특정 입력 액션에 연결된 키의 바인딩 또한 자유롭게 바꿀 수 있다.

키 입력 <--> 액션 이벤트 <--> 함수 실행

상태 패턴의 의의

스크립트 상에서 이벤트 구독으로 입력 시스템에 기능을 추가할 수 있다.
이말인즉슨 런타임 도중 특정 상황에 따라 이벤트 구독을 변경함으로써 같은 입력이지만 다른 기능을 수행할 수 있다는 뜻이다.

키보드와 마우스를 사용하는 PC게임을 개발할 때에는 입력에 대한 부족함을 느낄 수 없지만
많아야 손가락 한 두개를 사용하는 모바일 게임은 수행되는 기능에 비해 입력의 종류가 매우 제한적이다.
즉 손가락 하나로 터치를 하더라도 상황에 따라 수행되는 기능이 달라야 한다.

그런데 이를 하나의 거대한 함수 안에서 if 혹은 switch문으로 나누어 버리면 개발이 진행될수록 새로운 기능 추가와 유지보수가 어려워진다.

이럴 때 필요한 것이 상태 패턴이다. 상태 패턴은 동일한 오브젝트가 특정 상황에 따라 다른 행동을 취할 수 있게 해준다.

이를 입력 시스템과 조합하면 특정 상황에 따른 입력을 간단하게 분류 및 수행할 수 있고, 새로운 상황에 대한 행동 추가를 용이하게 할 수 있다.


구현

유니티 모바일 인풋 시스템

상태 패턴

다음의 게시글에는 모바일 인풋 시스템의 기초와 상태 패턴에 대한 기본적인 이론이 작성되어 있다.
위의 글을 읽고 오면 다음 내용을 이해하는 데 도움이 되리라 생각한다.

상태 머신에 이벤트 델리게이트 추가

상태 머신을 상속받고, C# 클래스로 생성된 인풋 시스템 레퍼런스를 가진 커스텀 입력 상태 머신을 구현하는 방법이다.

  1. 입력 상태 머신에 사용할 액션 이벤트에 대한 델리게이트를 생성한다.
/// <summary>
/// 첫 번째 손가락이 터치되었을 때 발생하는 이벤트
/// </summary>
internal delegate void PrimaryTouch();
internal event PrimaryTouch PrimaryTouchEvent;

/// <summary>
/// 첫 번째 손가락의 터치가 종료되었을 때 발생하는 이벤트
/// </summary>
internal delegate void PrimaryTouchEnd();
internal event PrimaryTouchEnd PrimaryTouchEndEvent;
  1. 입력 발생시 올바른 조건에서 델리게이트가 실행될 수 있도록 델리게이트 래핑 함수를 작성한다.
private void OnPrimaryTouch(InputAction.CallbackContext ctx)
{
    if (PrimaryTouchEvent != null
    && ctx.action.phase == InputActionPhase.Started
    && !EventSystem.current.IsPointerOverGameObject()
    && !IsPointerOverUIObject(PrimaryScreenPosition()))
    {
        PrimaryTouchEvent();
    }
}

private void OnPrimaryTouchEnd(InputAction.CallbackContext ctx)
{
    if (PrimaryTouchEndEvent != null
    && ctx.action.phase == InputActionPhase.Canceled)
    {
        PrimaryTouchEndEvent();
    }
}
  1. 생성한 델리게이트 래핑 함수를 인풋 시스템의 액션 이벤트에 구독시킨다.
private void OnEnable()
{
    _input.Enable();
    _input.Touch.PrimaryTouch.started += OnPrimaryTouch;
    _input.Touch.PrimaryTouch.canceled += OnPrimaryTouchEnd;
}

각 상태에서 이벤트 델리게이트에 기능 연결

상태 머신의 참조를 갖고 있는 각각의 상태에서 상태 머신에 선언해 둔 이벤트 델리게이트에 접근하는 방식이다.

  1. 상태로 전환되었을 때 원하는 기능을 델리게이트에 구독시키고, 상태에서 빠져 나올때 해당 기능의 구독을 해제한다.
public override void OnEnter()
{
    context.PrimaryTouchEvent += IdlePrimaryTouch;
    context.SecondaryTouchEvent += IdleSecondaryTouch;
}


public override void OnExit()
{
    context.PrimaryTouchEvent -= IdlePrimaryTouch;
    context.SecondaryTouchEvent -= IdleSecondaryTouch;
}
  1. 원하는 기능을 구현한다
private void IdlePrimaryTouch()
{
    Debug.Log("IdlePrimaryTouch");
    // Go to Swipe state
    stateMachine.ChangeState<OnSwipeAndTouch>();
}
        
private void IdleSecondaryTouch()
{
    Debug.Log("IdleSecondaryTouch");
    // Go to Pinch state
    stateMachine.ChangeState<OnPinch>();
}
profile
학습한 내용을 빠르게 다시 찾기 위한 저장소

1개의 댓글

comment-user-thumbnail
2023년 8월 5일

감사합니다. 이런 정보를 나눠주셔서 좋아요.

답글 달기