이번 포스트에서는 새로운 Input System을 사용한 UI 입력을 처리해보도록 하겠습니다.
우선, 두개의 버튼을 생성해보도록 하겠습니다.
생성하면 다음과 같이 Event System 오브젝트가 자동으로 생성되는 것을 볼 수 있습니다.
1) Event System이란?
UI 요소를 생성한 후에 자동으로 생성되는 EventSystem은 입력과 UI 요소를 연결해주는 오브젝트입니다.
생성된 EventSystem에서 기본적으로 총 3개의 컴포넌트가 있는데,
각각 Transform, Event System, 그리고 Input System UI Input Module입니다.
이중에서 Input System UI Input Module에서
새로운 Input System을 사용하게끔 설정하면 기본적인 Action Asset을 제공하여 사용할 수 있습니다.
해당 Action Asset에는 기본적으로 Player와 UI라는 Action Map이 제공됩니다.
2) UI 입력 수행 - 초기
Event System 컴포넌트에서는 First Selected 값을 설정해줄 수 있습니다.
First Selected 값에 사용할 UI를 설정해주면, 게임이 시작된 후에 해당 UI를 선택하게 됩니다.
그리고 생성한 2개의 버튼의 Selected Color를 설정하여 선택된 경우에 색을 변경하도록 하겠습니다.
이제 실행해보도록 하겠습니다.
동작은 원할하게 이뤄지고 있지만, 2개의 문제가 발생하고 있다는 것을 확인할 수 있습니다.
- 화면의 다른 부분을 클릭하면 버튼의 선택이 사라짐
- UI 입력과 기본 입력이 동시에 발생
따라서 위 2가지 문제를 해결하도록 하겠습니다.
3) UI 입력 수행 - 첫 번째 문제 해결
첫번째 문제의 해결방법은
Input System UI Input Module의 Deselect On Background 옵션을 해제하는 것입니다.
그리고 현재 설정된 Action Asset을 기본 제공되는 것이 아닌 직접 설계한 Action Asset으로 설정하겠습니다.
이후에 기존에 만든 Acion Asset에 기본제공되는 UI Action Map을 복사 붙여넣기하겠습니다.
중요한 절차가 하나 있는데, 반드시 올바른 Action Scheme으로 등록하는 것입니다.
키보드와 마우스로 수행하는 Input Action들을 각각 Keyboard와 Mouse로 등록하겠습니다.
확인해보면 Action Type이 Pass Through로 설정된 것을 볼 수 있는데,
이는 UI 입력 시 연결된 모든 장치로부터 입력이 전달되도록 설정하는 옵션입니다.
이후에 Player의 PlayerInput 컴포넌트에서 UI Input Module을 Event System으로 설정하겠습니다.
Action Asset을 사용하는 방식이 아닌 다른 방식의 경우, 이 절차는 생략가능합니다.
이제 실행결과를 살펴보겠습니다.
버튼의 선택이 사라지지는 않지만, 여전히 UI 입력이 동시에 처리되고 있습니다.
이제 이 문제를 수정해보도록 하겠습니다.
4) UI 입력 수행 - 두 번째 문제 해결
이 문제를 해결하는 방법은 여러 가지가 존재하므로 알아볼 방법이 유일한 방법은 아닙니다.
이 방법은 싱글 플레이어 방식의 게임에서 유리합니다.
주로 아이작의 구속이나, 파이널 판타지같은 방식의 게임에서 주로 볼 수 있는 방식입니다.
우선, 기존의 Action Asset에 새로운 Action Map을 추가하겠습니다.
그리고 기존의 코드를 다음과 같이 수정하겠습니다.
public class InvokeCSharpEvents : MonoBehaviour
{
// Player Input 컴포넌트
private PlayerInput playerInput;
// 수행할 Input Action
private InputAction attackAction;
private InputAction moveAction;
private InputAction menuActivateDeactivate;
// Action Map
private InputActionMap playerBasic;
private InputActionMap mapUI;
private InputActionMap mapSwitcher;
[SerializeField]
private float speed;
[SerializeField]
private GameObject canvas;
private Vector2 direction;
private Rigidbody2D rigidbody2D;
private void Awake()
{
rigidbody2D = GetComponent<Rigidbody2D>();
playerInput = GetComponent<PlayerInput>();
}
private void OnEnable()
{
playerBasic = playerInput.actions.FindActionMap("PlayerBasic");
mapUI = playerInput.actions.FindActionMap("UI");
mapSwitcher = playerInput.actions.FindActionMap("MapSwitcher");
// 우선, UI의 Action Map은 꺼놓음
mapUI.Disable();
moveAction = playerBasic.FindAction("Move");
attackAction = playerBasic.FindAction("Attack");
menuActivateDeactivate = mapSwitcher.FindAction("Menu");
attackAction.performed += AttackExample;
menuActivateDeactivate.performed += MenuControl;
// 그 외의 Action Map은 켜놓음
playerBasic.Enable();
mapSwitcher.Enable();
}
private void OnDisable()
{
playerBasic.Disable();
attackAction.performed -= AttackExample;
}
private void FixedUpdate()
{
direction = moveAction.ReadValue<Vector2>();
rigidbody2D.velocity = new Vector2(direction.x * speed, direction.y * speed);
}
private void AttackExample(InputAction.CallbackContext value)
{
Debug.Log("Attack");
}
// 사용할 Action Map을 저장할 지역변수
InputActionMap placeHolderActionMap;
private void MenuControl(InputAction.CallbackContext value)
{
// UI 캔버스가 null이면 얼리 리턴
if (canvas == null)
return;
// Action Map을 저장하고 있는 지역변수가 null이라면,
// PlayerInput 컴포넌트로부터 현재 사용중인 Action Map을 받아 저장
if (placeHolderActionMap == null)
placeHolderActionMap = playerInput.currentActionMap;
// UI 캔버스가 비활성화 상태라면
if (!canvas.activeSelf)
{
// 플레이어 입력 Action Map을 끄고, UI Action Map을 켜놓음
playerBasic.Disable();
mapUI.Enable();
// UI 캔버스를 활성화하고, UI Action Map을 현재 사용중인 Action Map으로 설정
canvas.SetActive(true);
playerInput.SwitchCurrentActionMap(mapUI.name);
}
// UI 캔버스가 활성화 상태라면
else
{
// UI Action Map을 끄고, 플레이어 입력 Action Map을 켜놓음
mapUI.Disable();
playerBasic.Enable();
// UI 캔버스를 비활성화하고, 플레이어 Action Map을 현재 사용중인 Action Map으로 설정
// Action Map을 저장하는 변수는 null로 날려줌
canvas.SetActive(false);
playerInput.SwitchCurrentActionMap(placeHolderActionMap.name);
placeHolderActionMap = null;
}
}
}
하이어아키 창에서 다음과 같이 설정하겠습니다.
실행결과는 다음과 같습니다.
문제없이 잘 실행되는 것을 볼 수 있습니다.
'유니티 > 유니티 C#' 카테고리의 다른 글
유니티 입력 처리 심화 - (13) Action Asset에서의 Index와 Composite (0) | 2025.01.23 |
---|---|
유니티 입력 처리 심화 - (11) Player Input 컴포넌트 - Invoke C# Events (0) | 2025.01.05 |
유니티 입력 처리 심화 - (10) Player Input 컴포넌트 - Invoke Unity Events (0) | 2025.01.04 |
유니티 입력 처리 심화 - (9) Player Input 컴포넌트 - Broadcast Messages (0) | 2025.01.02 |
유니티 입력 처리 심화 - (8) Player Input 컴포넌트 - Send Messages (0) | 2025.01.02 |