추가 설명 들어가겠습니다. 이번 기회를 통해 확실히 이해합시다.
ActionMap 분류와 사용 방법
ActionMap 활성화/비활성화
InputActionMap은 상황에 따라 필요한 시점에서만 활성화되도록 관리합니다.
예를 들어:
Player ActionMap: 캐릭터 움직임, 점프 같은 입력 처리.
활성화: 게임 플레이 중.
UI ActionMap: 메뉴 내비게이션, 버튼 클릭 같은 입력 처리.
활성화: UI를 열었을 때.
코드 예제: ActionMap 활성화/비활성화
private PlayerControls controls; private void Awake() { // Input System 초기화 controls = new PlayerControls(); } private void OnEnable() { // 기본적으로 Player ActionMap 활성화 controls.Player.Enable(); // UI는 기본적으로 비활성화 controls.UI.Disable(); } private void OnDisable() { // ActionMap 모두 비활성화 controls.Player.Disable(); controls.UI.Disable(); } // UI 열고 닫을 때 ActionMap 스위칭 public void ToggleUI(bool isUIActive) { if (isUIActive) { // UI 활성화, Player 비활성화 controls.UI.Enable(); controls.Player.Disable(); } else { // Player 활성화, UI 비활성화 controls.Player.Enable(); controls.UI.Disable(); } }
두 개의 InputActionAsset으로 분리하는 경우
InputActionAsset 분리 playerControl → 캐릭터 조작용 InputActionMap만 포함 (e.g., Player) uiControl → UI 조작용 InputActionMap만 포함 (e.g., UI)
using UnityEngine; using UnityEngine.InputSystem; public class InputManager : MonoBehaviour { public InputActionAsset playerControl; // Player ActionAsset public InputActionAsset uiControl; // UI ActionAsset private InputActionMap playerMap; private InputActionMap uiMap; private void Awake() { // 각각의 ActionMap 가져오기 playerMap = playerControl.FindActionMap("Player"); uiMap = uiControl.FindActionMap("UI"); } private void OnEnable() { // 초기 활성화 설정 playerMap.Enable(); uiMap.Disable(); } private void OnDisable() { // 모두 비활성화 playerMap.Disable(); uiMap.Disable(); } public void ToggleUI(bool isUIActive) { if (isUIActive) { uiMap.Enable(); // UI 활성화 playerMap.Disable(); // Player 비활성화 } else { playerMap.Enable(); // Player 활성화 uiMap.Disable(); // UI 비활성화 } } }
분리와 통합의 차이
(1) 분리하는 경우
각각의 InputActionAsset을 독립적으로 로드, 관리.
서로 완전히 독립된 입력 구조를 원할 때 사용.
예를 들어:
playerControl: 캐릭터 조작에만 필요한 입력 (Move, Jump 등).
uiControl: UI 탐색용 입력 (Navigate, Submit 등).
(2) 통합하는 경우
하나의 InputActionAsset 안에 여러 InputActionMap을 포함.
관리가 단순화되고, 활성화/비활성화만으로 전환 가능.
권장되는 기본 방식:
PlayerControls.inputactions 파일 하나로 처리.
위 예시처럼 Player와 UI를 같은 Asset에 두고 관리.
playerControl은 사실상 그 Input Action에 있는 진짜 Player (InputActionMap)을 가리키는 건 아니며, 사실상 참조의 개념인데,그렇게 된다면 실제로 InputActionMap playerMap;도 그렇고 Player라는 InputAcitonMap을 연결해서 즉, 실제로 저것을 쓸 연결자체가 없다는 뜻인데, 어떻게 연결된 것처럼 쓸 수 있냐 이 궁금증이 생겼습니다.
public InputActionAsset playerControl;은 InputActionAsset 전체를 참조하는 거지, 내부의 특정 InputActionMap (Player)을 직접 가리키는 건 아닙니다. 그런데도 playerMap = playerControl.FindActionMap("Player");처럼 특정 InputActionMap을 연결해서 사용할 수 있는 이유가 있습니다.
핵심 이유: InputActionAsset의 구조
InputActionAsset은 여러 InputActionMap의 컨테이너
InputActionAsset은 내부적으로 여러 InputActionMap(예: Player, UI)을 포함하고 있고, 이를 이름으로 검색할 수 있습니다.
그래서 playerControl.FindActionMap("Player")를 호출하면, InputActionAsset 내부의 "Player"라는 이름의 InputActionMap을 가져오는 것입니다.
FindActionMap 메서드로 연결 가능
InputActionAsset의 FindActionMap(string name) 메서드를 사용하면, 이름으로 특정 InputActionMap을 검색해서 가져올 수 있어. 이 검색이 바로 연결의 역할을 하는 것입니다.
가져온 InputActionMap은 실제로 InputActionAsset 안에 포함된 Player라는 ActionMap을 참조하게 되는 것입니다.
InputActionMap은 InputActionAsset 내부의 데이터로 관리됩니다. FindActionMap을 통해 반환된 InputActionMap 객체는 여전히 원래 InputActionAsset 내부 데이터를 참조하고 있습니다. 그래서 InputActionMap을 수정하거나 실행하면 해당 InputActionAsset 데이터가 적용되는 구조입니다.
즉, 전체 정보를 들고 있는 인스턴스를 생성하는데, 그것에 접근하기 위해 FindMap이나 FindAction등 여러가지 방법으로 접근을 해야 합니다.
근데.....
public InputActionAsset
private InputActionMap
private InputAction
이 놈들은 뭔데 자꾸 따로 나오는 걸까요?
InpuActionAsset은 이미 모든 정보를 들고 있는데, 밑에 저놈들은 뭘까요? 가독성을 위해?
1. 핵심 구조
(1) InputActionAsset
InputActionAsset은 Input System의 최상위 컨테이너입니다.
하나의 InputActionAsset 파일에 여러 개의 InputActionMap과 각 InputActionMap에 속한 여러 개의 InputAction이 포함됩니다.
이게 바로 입력 데이터의 실제 저장소 역할을 합니다.
즉, 파일 내의 모든 입력 데이터를 들고 있는 녀석이라고 보면 됩니다.
(2) InputActionMap
InputActionMap은 논리적 그룹입니다.
예를 들어:
Player: 캐릭터 조작 관련 입력 묶음입니다.
UI: UI 탐색 관련 입력 묶음.
InputActionAsset 안에 정의된 각각의 InputActionMap은 독립적으로 활성화/비활성화하거나 사용할 수 있도록 설계됩니다.
하지만 InputActionMap 자체는 데이터를 직접 보관하지 않습니다.
대신, InputActionAsset 안의 데이터를 참조해서 동작할 뿐입니다.
(3) InputAction
InputAction은 개별적인 입력 동작을 정의합니다.
예: "Move", "Jump", "Navigate", "Submit".
InputActionMap 안에 소속돼 있지만, 실제 데이터는 InputActionAsset에 저장돼 있습니다.
마찬가지로 InputAction도 자체적으로 데이터를 들고 있지 않고, InputActionAsset 데이터를 기반으로 동작합니다.
그렇다면 왜 InputActionMap과 InputAction이 따로 존재할까?
(1) 객체 지향적인 설계
Unity의 Input System은 가독성과 유연성을 위해 객체 지향적으로 설계됐습니다:
InputActionAsset은 모든 입력 데이터를 저장.
InputActionMap과 InputAction은 데이터의 사용을 쉽게 도와주는 추상화된 객체입니다.
(2) 독립적인 컨텍스트 관리
InputActionMap은 서로 독립적으로 활성화/비활성화할 수 있습니다.
이렇게 하면 InputActionAsset 전체를 통째로 관리하는 대신, 특정 맵만 켜고 끄는 게 가능합니다.
(2) 동작 예제
// InputActionAsset을 통해 InputActionMap을 가져오기 private InputActionMap playerMap = playerControl.FindActionMap("Player"); // 특정 InputAction 가져오기 private InputAction moveAction = playerMap.FindAction("Move"); // InputAction 동작 연결 moveAction.performed += ctx => Debug.Log("Move: " + ctx.ReadValue<Vector2>());
위 코드에서:
playerControl.FindActionMap("Player"): InputActionAsset에서 "Player"라는 이름의 InputActionMap을 가져옴.
playerMap.FindAction("Move"): InputActionMap에서 "Move"라는 이름의 InputAction을 가져옴.
moveAction은 InputActionAsset 내부 데이터에 연결된 상태로 동작.
InputActionMap과 InputAction은 무엇을 가리키는가?
(1) 데이터의 역할
InputActionAsset은 데이터를 들고 있음.
InputActionMap과 InputAction은 참조 객체로서 데이터를 가져와 사용하는 역할을 합니다.
(2) 직접 연결되지 않는 이유
InputActionMap과 InputAction은 필요할 때 InputActionAsset에서 데이터를 검색해 사용하도록 설계돼 있습니다.
따라서, InputActionMap과 InputAction은 독립적인 실행 객체처럼 동작하지만, 실제 데이터는 항상 InputActionAsset에 저장됩니다.
핵심 포인트: InputActionAsset, InputActionMap, InputAction의 연결
public InputActionAsset playerControl;와 같은 선언을 보면, playerControl은 InputActionAsset을 참조하지만, InputActionMap이나 InputAction과는 직접적인 연결이 없어 보이게 됩니다. 그렇다면 왜 이 코드에서 연결이 되는지 이해하려면 InputActionAsset과 그 안의 InputActionMap 및 InputAction 객체 간의 연결 메커니즘을 살펴봐야 합니다.
InputActionAsset과 InputActionMap 연결
InputActionAsset은 여러 개의 InputActionMap을 포함하는 컨테이너 역할을 합니다.
예를 들어, playerControl은 InputActionAsset을 참조하고 있고, 그 안에 여러 InputActionMap (Player, UI)이 들어 있는 구조입니다.
playerControl.FindActionMap("Player")와 같은 방법으로 InputActionMap을 찾아서 사용하지만, InputActionMap은 기본적으로 InputActionAsset을 통해 관리되기 때문에 그 안의 데이터를 사용할 수 있습니다. 즉, 서로 묶여진 하나의 덩어리이기 때문에 쓸 수 있는 것입니다.
InputActionAsset에서 InputActionMap을 찾는 과정public InputActionAsset playerControl; // 전체 InputActionAsset 참조 private InputActionMap playerMap; // 특정 InputActionMap 참조 private void Awake() { // InputActionAsset에서 "Player"라는 이름의 InputActionMap을 찾음 playerMap = playerControl.FindActionMap("Player"); }
playerControl은 InputActionAsset 객체이고, 그 안에 여러 InputActionMap이 있을 수 있습니다.
FindActionMap("Player") 메서드를 호출하면, InputActionAsset에서 "Player"라는 이름의 InputActionMap을 찾아 반환합니다.
반환된 playerMap은 playerControl 내부에서 "Player"라는 InputActionMap을 참조하게 됩니다.
InputActionMap에서 InputAction을 찾는 과정private InputAction moveAction; private void Awake() { // "Player"라는 InputActionMap에서 "Move"라는 InputAction을 찾음 moveAction = playerMap.FindAction("Move"); // Move Action에 대한 이벤트 연결 moveAction.performed += ctx => Move(ctx.ReadValue<Vector2>()); }
하지만 또 다른 이유가 있습니다public InputActionAsset playerControl; // Player ActionAsset public InputActionAsset uiControl; // UI ActionAsset private InputActionMap playerMap; private InputActionMap uiMap; private void Awake() { // 각각의 ActionMap 가져오기 playerMap = playerControl.FindActionMap("Player"); uiMap = uiControl.FindActionMap("UI"); }
아니 그런데 저 playerMap은 왜 저렇게 playerControl.FindActionMap에서 값을 받지?라고 하실 수 있습니다.
어떻게 보면 playerControl.FindActionMap("Player");에서 저건 반환하는 타입에 맞춰서 변수를 써야하는데,playerMap = playerControl.FindActionMap("Player");
실제로 이전에서도 설명했듯이, 반환하는 타입은 같은 타입만 받을 수 있다라고 했듯이, playerControl.FindActionMap("Player");이 반환하는 타입은 FindActionMap을 통해 InputActionMap 타입을 반환하기 때문에 먼저 InputActionMap 타입을 가지는 playerMap을 선언해서 그것을 받게한 것 입니다.
추가로 설명하자면, playerControl은 InputActionAsset 타입이며, FindActionMap("Player")는 InputActionAsset 클래스에 정의된 메서드로, InputActionMap을 반환합니다.
즉, InputActionAsset은 여러 InputActionMap을 포함하고 있는 객체이고, FindActionMap() 메서드는 이름을 기준으로 특정 InputActionMap을 찾는 메서드입니다.public InputActionAsset playerControl; // InputActionAsset 참조 private InputActionMap playerMap; // InputActionMap 참조 private void Awake() { // playerControl은 InputActionAsset이고, // FindActionMap은 InputActionMap을 반환합니다. playerMap = playerControl.FindActionMap("Player"); // "Player"라는 이름의 InputActionMap 반환 }
FindActionMap("Player")가 반환하는 것은 InputActionMap이고, 이는 playerMap 변수에 할당됩니다.
playerMap은 InputActionMap 타입으로 선언되어야 하고, 그 안에서 특정 InputAction을 찾아 사용할 수 있습니다.
InputActionMap이 왜 반환 가능한지
InputActionMap은 InputActionAsset의 구성 요소이기 때문에 FindActionMap() 메서드를 통해 검색 가능합니다.
InputActionAsset이 여러 개의 InputActionMap을 포함하고 있지만, 각 InputActionMap은 독립적으로 존재할 수 있으며, 이게 바로 InputActionMap이 반환되는 이유입니다.
결론
InputActionAsset이 실제 데이터를 가지고 있는 건 맞아.
InputActionMap과 InputAction은 데이터가 아니라 참조 객체야.
이들은 데이터를 들고 있지 않고, InputActionAsset과 연결돼 있습니다.
왜 따로 있는지에 대한 답은 유연성 때문:
InputActionMap으로 독립적인 컨텍스트 관리.
InputAction으로 개별 입력 동작 처리.
이 구조 덕분에 코드 가독성과 유지보수성이 좋아지는 것입니다.
GetAxis
이제 뭐 GetKeyDown이런거 제치고 GetAxis를 가봅시다.
Input.GetAxis를 이용해서 수평, 수직 버튼을 받으면 float을 주는 그런 형식입니다.
그런데 이건 예전 버전에서 쓰던 것.....자, 우리는 뭐다? 바로바로 Input Manager가 아니라, Input System으로 봐야합니다.
Input Actions 생성(참고로 새로운 Input Action은 Input.GetAxis를 더 이상 사용하지 않습니다)
Input.GetAxis와 새로운 Input System 비교
Input.GetAxis: 기존 방식에서는 Unity의 축 이름("Horizontal", "Vertical" 등)을 사용해 매 프레임 입력을 가져왔습니다.
새로운 방식: Input Action에서 Vector2 타입의 입력을 정의하여 WASD, 화살표 키, 게임패드 스틱 등의 입력을 모두 처리할 수 있습니다.
프로젝트에서 Input Actions 에셋을 생성합니다.
"Move"와 같은 액션을 정의하고, WASD 키나 게임패드 조이스틱 등을 바인딩합니다.
Player Input 컴포넌트 추가
캐릭터 또는 플레이어 GameObject에 Player Input 컴포넌트를 추가하고, 생성한 Input Actions 에셋을 연결합니다.
스크립트로 입력 처리
Input System에서는 콜백 또는 InputAction 객체를 통해 입력을 처리합니다.
먼저 콜백 메서드에 대해 배워보겠습니다(왜냐하면, 새로운 Input System에서는 Input Action Asset을 사용하여 입력을 정의하고, 콜백 메서드를 통해 입력을 처리합니다.)
Unity에서 Input System을 사용할 때, 콜백 메서드(callback method)는 특정 입력 이벤트가 발생했을 때 호출되는 메서드를 의미해요. 쉽게 말해서, 플레이어가 키보드를 누르거나 마우스를 클릭하는 등의 입력을 감지했을 때, 미리 지정된 메서드가 자동으로 실행되도록 설정하는 방식이에요.
주요 개념
Input Action Asset:
Unity Editor에서 입력(키보드, 마우스, 게임패드 등)을 미리 정의한 설정 파일입니다.
입력을 "액션"으로 정의하고, 각 액션을 다양한 디바이스에 매핑합니다.
이벤트 기반 처리:
특정 입력이 발생했을 때, 미리 정의한 콜백 메서드가 호출됩니다.
콜백 메서드가 작동하는 방식:
Input Action을 생성하고, 특정 입력(예: 키보드, 마우스, 게임패드 등)을 트리거로 연결.
Input Action이 트리거되었을 때 실행될 콜백 메서드를 작성.
해당 메서드를 Input Action에 연결.
새로운 Input System에서 축 입력 처리
1. Input Action Asset 설정
Input Actions 에셋 생성:
Assets > Create > Input Actions로 새 에셋을 만듭니다.
Move 액션 정의:
액션 이름: Move
Action Type: Value
Control Type: Vector2
Move에 입력 매핑 추가:
키보드: WASD 또는 화살표 키.
게임패드: Left Stick (게임패드의 축 입력).
스크립트 작성
아래는 새로운 Input System에서 축 입력을 처리하는 코드입니다.
using UnityEngine; using UnityEngine.InputSystem; public class PlayerController : MonoBehaviour { private PlayerInputActions inputActions; private Vector2 moveInput; private void Awake() { // Input Actions 인스턴스 생성 inputActions = new PlayerInputActions(); // Move 액션 콜백 연결 inputActions.Player.Move.performed += OnMovePerformed; inputActions.Player.Move.canceled += OnMoveCanceled; } private void OnEnable() { inputActions.Enable(); } private void OnDisable() { inputActions.Disable(); } private void OnMovePerformed(InputAction.CallbackContext context) { // Vector2 입력값 가져오기 (축 입력 처리) moveInput = context.ReadValue<Vector2>(); Debug.Log($"Move Input: {moveInput}"); } private void OnMoveCanceled(InputAction.CallbackContext context) { // 입력이 취소될 경우 값 초기화 moveInput = Vector2.zero; Debug.Log("Move Input Canceled"); } private void Update() { // 입력값을 사용해 캐릭터 이동 처리 Vector3 move = new Vector3(moveInput.x, 0, moveInput.y); transform.Translate(move * Time.deltaTime * 5f); } }
주요 차이점
축 이름 없음:
Input.GetAxis("Horizontal")처럼 축 이름으로 호출하지 않고, Input Action에서 미리 정의한 Vector2 입력을 가져옵니다.
Vector2로 축 입력 처리:
moveInput.x: Horizontal(좌/우).
moveInput.y: Vertical(위/아래).
멀티 디바이스 지원:
동일한 Move 액션으로 키보드, 게임패드, 터치스크린 입력을 모두 처리할 수 있습니다.
'Unity 개인 공부' 카테고리의 다른 글
Unity 개인 공부(2025-01-30) (0) | 2025.01.30 |
---|---|
Unity 개인 공부(2025-01-23) (0) | 2025.01.23 |
Unity 개인 공부(2025-01-22) (2) | 2025.01.22 |
Unity 개인 공부(2025-01-21) (0) | 2025.01.21 |
Unity 개인 공부(2025-01-20) (0) | 2025.01.20 |