InputActionAsset asset = new InputActionAsset();
InputActionAsset anotherReference = asset;
// asset과 anotherReference는 같은 객체를 참조
하....답답합니다...예? 왜냐구요? 이게.....input 시스템은 초보자가 하기에는 어려운 개념이긴 하지만, 사실상 기초 단계에서는 무조건 잡고 가야하는 개념이니....예...뭐....해야죠...
그전에 참조라는 것을 배워보겠습니다.
public InputActionAsset inputActions;
private InputAction jumpAction;
이런거 이런거...그때 설명을 했지만....이게 아직 잘 이해가 안 가서...
찾아보니 참조라는 개념이더군요.
먼저, C#에서 클래스는 참조 타입(reference type)입니다.
즉, InputActionAsset inputActions;는 inputActions라는 변수가 InputActionAsset 객체를 참조할 수 있는 참조(포인터와 유사한 개념)를 나타냅니다.
public InputActionAsset inputActions; // inputActions는 InputActionAsset을 "참조"함.
참조가 가지는 의미
변수 inputActions는 InputActionAsset 객체를 가리킬 수 있지만, 객체 자체를 저장하지는 않습니다.
객체 자체는 메모리(힙)에 존재하고, inputActions는 그 메모리 위치를 참조하게 됩니다.InputActionAsset asset = new InputActionAsset(); InputActionAsset anotherReference = asset; // asset과 anotherReference는 같은 객체를 참조
여기서 중요한 점은, 두 변수가 같은 객체를 참조할 경우, 하나의 변수를 통해 변경한 내용은 다른 참조에도 영향을 줍니다.
InputActionAsset이 어떻게 사용되나?
Unity의 Input System에서 InputActionAsset은 입력 데이터를 정의하고 관리하는 클래스입니다.
InputActionAsset은 ScriptableObject 형태로 저장된 파일을 참조합니다.
즉, inputActions는 프로젝트에 저장된 Input Action Asset을 참조하는 변수가 됩니다.public InputActionAsset inputActions; // 유니티 에디터에서 Input Action Asset 파일을 연결
Unity 에디터에서 이 변수에 Input Action Asset 파일을 드래그 앤 드롭하면, 해당 ScriptableObject의 참조가 inputActions 변수에 저장됩니다.
값이 들어가는가, 참조인가?
inputActions는 값(value) 자체가 아니라, InputActionAsset 객체를 가리키는 참조(reference)입니다.
예를 들어:
InputActionAsset이라는 Input Asset 파일을 Unity에서 생성합니다.
Unity 에디터에서 inputActions에 Input Asset 파일을 연결합니다.
이제 inputActions는 Input Asset 파일을 참조하며, 이를 통해 정의된 입력 데이터를 사용할 수 있습니다.
참조의 의미 정리
참조는 "이 변수가 특정 객체를 가리키고 있다"는 의미입니다.
객체는 힙 메모리에 저장되고, 변수를 통해 객체를 간접적으로 조작합니다.
inputActions는 InputActionAsset 객체(파일)의 메모리 위치를 참조하며, 이를 통해 Input System 데이터를 관리하거나 사용할 수 있습니다.public class MyInputHandler : MonoBehaviour { public InputActionAsset inputActions; // InputActionAsset을 참조하는 변수 void Start() { // inputActions에 연결된 Asset에서 특정 Action 찾기 InputAction jumpAction = inputActions.FindAction("Jump"); // Action에 이벤트 연결 jumpAction.performed += ctx => Debug.Log("Jumped!"); jumpAction.Enable(); // 액션 활성화 } }
inputActions는 InputActionAsset 파일을 참조합니다.
FindAction을 호출하면, 참조된 객체에서 "Jump" 액션을 검색합니다.
액션이 활성화되면 실제 입력 이벤트를 처리합니다.
더 쉽게 말하자면,
참조(reference)는 객체가 메모리의 어디에 저장되어 있는지를 나타내는 일종의 "주소"입니다.
InputActionAsset 같은 참조 타입의 변수를 사용하면, 그 변수는 실제 데이터를 담고 있는 객체를 직접 가지는 것이 아니라 그 객체가 있는 메모리 위치를 가리킵니다.InputActionAsset asset1 = new InputActionAsset(); InputActionAsset asset2 = asset1; // asset2는 asset1이 가리키는 객체를 "참조" asset1.name = "ChangedName"; // asset1을 통해 값을 바꿈 Console.WriteLine(asset2.name); // asset2로도 바뀐 이름 확인 가능: "ChangedName"
간접 접근과 변형
참조 타입 변수는 객체 내부의 데이터에 간접적으로 접근하고, 데이터를 읽거나 수정할 수 있습니다.
만약 두 변수가 같은 객체를 참조하고 있다면, 한 변수를 통해 데이터를 변경하면 다른 변수에서도 동일한 변경 내용이 보입니다.class MyClass { public int value; } MyClass obj1 = new MyClass(); obj1.value = 42; MyClass obj2 = obj1; // obj1과 같은 객체를 참조 obj2.value = 100; Console.WriteLine(obj1.value); // 100 (obj2를 통해 수정한 값이 반영됨)
같은 클래스를 사용한다는 의미
같은 클래스를 사용한다고 해서 모든 변수가 동일한 데이터를 공유하지는 않습니다.
각각 새로운 객체를 생성하면, 같은 클래스 타입이어도 서로 독립적인 데이터를 가집니다.MyClass obj1 = new MyClass(); obj1.value = 42; MyClass obj2 = new MyClass(); obj2.value = 100; Console.WriteLine(obj1.value); // 42 (서로 다른 객체) Console.WriteLine(obj2.value); // 100
하지만, 같은 객체를 참조한다면 데이터가 공유됩니다.MyClass obj1 = new MyClass(); obj1.value = 42; MyClass obj2 = obj1; // obj2와 obj1이 같은 객체를 참조 obj2.value = 100; Console.WriteLine(obj1.value); // 100 (obj2를 통해 변경됨)
결론적으로
참조 타입 변수는 객체의 메모리 주소를 저장하며, 객체 내부의 데이터를 간접적으로 조작합니다.
두 변수가 같은 객체를 참조하면, 하나의 변수를 통해 객체의 데이터를 변경하면 다른 변수에서도 변경된 데이터가 보입니다.
서로 다른 객체를 생성하면, 같은 클래스 타입이라도 데이터가 독립적입니다.
자, 천천히 해봅시다.
using UnityEngine; using UnityEngine.InputSystem; public class PlayerInput : MonoBehaviour { public InputActionAsset inputActions; // InputActions 파일을 연결할 변수 private InputAction jumpAction; // Jump 액션을 위한 변수 private void OnEnable() { // 입력 액션을 로드하고, 'Jump' 액션을 찾습니다. jumpAction = inputActions.FindAction("Player Controls/Jump"); jumpAction.Enable(); // 액션 활성화 } private void Update() { if (jumpAction.triggered) { Debug.Log("Jump Button Pressed!"); } } private void OnDisable() { jumpAction.Disable(); // 액션 비활성화 } }
자, 지난건 잊으시고 천천히 하나하나
public InputActionAsset inputActions;
먼저, InputActionAsset은 Unity의 새로운 Input System에서 사용되는 핵심 클래스 중 하나로, 입력 데이터(Action Map과 Input Actions)를 관리하는 파일입니다. 기존 Input Manager처럼 여러 입력을 정의하고 구조화된 방식으로 관리할 수 있도록 해줍니다. (참조 타입)
InputActionAsset의 역할 Action Map: 여러 개의 입력 액션 그룹을 담습니다. (예: "Player Controls", "UI Controls") Input Actions: 특정 키 동작을 정의합니다. (예: "Jump", "Move", "Shoot") Binding: 각 액션에 연결된 키/버튼을 정의합니다. (예: "Space" 키가 "Jump"에 바인딩됨) InputActionAsset 파일은 이런 데이터들을 포함하며, 이를 코드로 불러와 사용하거나 수정할 수 있습니다.
그런데 질문이 하나 생기지 않습니까? 이미 InputAction은 InputActionAsset을 참조하는데 왜 굳이 그것을 또 jumpAction에게 참조하게 두는걸까요?
핵심은 InputActionAsset은 모든 입력을 관리하는 상위 개념이지만, 실제로 특정 입력(예: Jump)을 처리하기 위해선 개별 InputAction 객체가 필요하기 때문입니다.
InputActionAsset은 전체 입력 데이터를 관리
InputActionAsset은 모든 입력 데이터를 포함한 큰 데이터베이스 역할을 합니다.
예를 들어, 다음과 같은 구조를 가질 수 있습니다:
InputActionAsset: - Action Map: "Player Controls" - Action: "Move" - Action: "Jump" - Action: "Shoot" - Action Map: "UI Controls" - Action: "Navigate" - Action: "Select"
이처럼 InputActionAsset은 "Player Controls"나 "UI Controls" 같은 여러 액션 맵을 관리하며, 그 안에는 각 액션(Move, Jump, Shoot)이 포함되어 있습니다.
특정 액션에 접근하려면 InputAction 객체가 필요
InputActionAsset은 전체 데이터를 관리하지만, 개별 액션을 다룰 때는 InputAction 객체가 필요합니다. 이는 두 가지 이유 때문입니다:
1) 명확한 역할 분리
InputActionAsset은 모든 액션을 관리하지만, 게임에서는 보통 특정 동작에만 관심이 있습니다.
예를 들어, 플레이어 캐릭터의 점프 동작만 처리하려고 할 때, "Player Controls"의 "Jump" 액션만 신경 쓰면 됩니다.
다른 액션("Move", "Shoot" 등)은 필요하지 않으므로, 코드에서 불필요하게 액션 전체를 참조할 이유가 없습니다.
효율성
InputActionAsset에서 매번 특정 액션을 검색(FindAction)하면 비효율적입니다. 예:var jumpAction = inputActions.FindAction("Player Controls/Jump"); if (jumpAction.triggered) { Debug.Log("Jumped!"); }
매 프레임마다 FindAction을 호출하면 성능에 영향을 줄 수 있습니다.
대신, jumpAction을 초기화 시점에 한 번만 설정해 두고 반복적으로 사용하면 성능적으로 더 효율적입니다.
InputAction 객체의 실질적인 역할
InputAction 객체는 입력 동작을 처리하는 실질적인 도구입니다. 다음과 같은 기능을 제공합니다:
1) 입력 상태 확인
예: 특정 키가 눌렸는지, 뗐는지, 지속적으로 눌리고 있는지 등을 실시간으로 확인할 수 있습니다.if (jumpAction.triggered) { Debug.Log("Jump Triggered!"); }
왜 jumpAction으로 따로 저장할까요?
1) 코드 가독성
jumpAction을 사용하면 코드가 더 간결하고 가독성이 좋아집니다.
예: 특정 액션만 다룰 때.if (jumpAction.triggered) { Debug.Log("Jump!"); }
FindAction을 매번 호출하면 코드가 복잡해질 수 있습니다:if (inputActions.FindAction("Player Controls/Jump").triggered) { Debug.Log("Jump!"); }
2) 재사용성
jumpAction 변수를 사용하면, 초기화 후 재사용할 수 있어 효율적입니다.
FindAction을 매번 호출하지 않아도 되고, 특정 동작을 지속적으로 처리할 수 있습니다.
3) 명확한 컨트롤
jumpAction은 특정 입력 동작을 처리하는 데 초점을 맞추고 있습니다.
이를 통해 여러 액션을 독립적으로 관리할 수 있습니다.
그런데 이러면InputActionAsset jumpAction = inputActions.FindAction("Player Controls/Jump");
이렇게 지정해도 되지 않을까요?
이렇게 한 번만 초기화하고 사용하면 가독성 면에서는 문제가 없습니다. 하지만 정확히 따지면, 이렇게 작성하는 경우 코드에서 타입 불일치가 생깁니다.
FindAction 메서드의 반환값은 InputAction 타입입니다.
즉, inputActions.FindAction("Player Controls/Jump")의 반환값은 InputAction이고, 이를 InputActionAsset 타입의 변수에 저장하려고 하면 컴파일 오류가 발생합니다.
올바르게 작성하려면 이렇게 해야 합니다:InputAction jumpAction = inputActions.FindAction("Player Controls/Jump");
왜 InputActionAsset 타입으로 하면 안 될까요?
InputActionAsset은 전체 입력 데이터를 관리하는 상위 개념입니다. 반면, FindAction은 특정 액션(InputAction)을 반환하므로, 반환 타입이 달라서 문제가 생깁니다.
올바른 코드:InputAction jumpAction = inputActions.FindAction("Player Controls/Jump");
컴파일 오류가 나는 코드:InputActionAsset jumpAction = inputActions.FindAction("Player Controls/Jump"); // ❌
오류 이유: FindAction은 InputAction을 반환하므로, InputActionAsset 타입으로 할당할 수 없습니다.
그러면InputActionAsset jumpAction = InputActionAsset.FindAction("Player Controls/Jump");
이건 될까요? 이것도 안됩니다.
InputActionAsset.FindAction()은 존재하지 않아서 InputActionAsset 타입에서 바로 FindAction()을 호출하는 것은 불가능합니다. 대신, FindAction()은 InputActionAsset의 인스턴스 메서드로 제공되며, 따라서 반드시 특정 InputActionAsset 객체에서 호출해야 합니다.
1. FindAction은 인스턴스 메서드
FindAction은 InputActionAsset의 인스턴스 메서드입니다.
즉, 특정 InputActionAsset 객체(예: inputActions)를 통해 호출해야 합니다.
정적 메서드(static)가 아니므로, 다음과 같은 방식으로 호출해야 합니다:InputAction jumpAction = inputActions.FindAction("Player Controls/Jump");
InputActionAsset.FindAction()처럼 사용하려면?
InputActionAsset 클래스가 FindAction 메서드를 정적(static)으로 제공하지 않으므로, 다음과 같은 방식은 사용할 수 없습니다:InputActionAsset jumpAction = InputActionAsset.FindAction("Player Controls/Jump"); // ❌
여기서 정적(static) 메서드와 인스턴스(instance) 메서드의 차이를 알아야합니다.
정적 메서드(static method):
클래스 자체에 속하며, 특정 객체를 생성하지 않아도 호출할 수 있는 메서드입니다.
클래스 이름을 통해 호출합니다.
정적 메서드는 특정 객체의 상태(필드나 프로퍼티 등)에 접근할 수 없습니다.public class MathUtils { public static int Add(int a, int b) { return a + b; } }
호출:
int result = MathUtils.Add(3, 5); // 객체 없이 호출 가능
인스턴스 메서드(instance method):
특정 객체에 속하며, 그 객체의 상태(필드, 프로퍼티 등)에 의존합니다.
객체를 생성한 후 해당 객체를 통해 호출해야 합니다.public class Calculator { public int baseValue; public int Add(int value) { return baseValue + value; // 객체의 상태에 의존 } }
호출
Calculator calculator = new Calculator(); calculator.baseValue = 10; int result = calculator.Add(5); // 객체를 통해 호출해야 함
왜 InputActionAsset.FindAction은 정적 메서드가 아닐까?
InputActionAsset의 설계를 보면, FindAction은 특정 입력 액션을 검색하는 기능을 제공합니다.
이 메서드는 InputActionAsset 객체의 데이터를 기반으로 동작하므로, 정적 메서드로 만들 수 없습니다.
주요 이유:
객체의 데이터에 의존:
FindAction은 특정 InputActionAsset 객체에 포함된 액션 맵과 액션들을 검색합니다.
다른 InputActionAsset 객체에는 다른 액션 맵이 있을 수 있으므로, 어떤 데이터를 검색할지 명확하지 않습니다.
따라서 FindAction은 인스턴스 메서드로 구현되어 있습니다.
다중 InputActionAsset 관리:
한 프로젝트에서 여러 InputActionAsset을 사용할 수 있습니다.
정적 메서드로 만들면, 어떤 InputActionAsset을 기준으로 동작해야 할지 알 수 없습니다.
정적 메서드로 만들면 어떤 문제가 생길까?
만약 Unity가 FindAction을 정적 메서드로 만들었다고 가정해 본다면:InputAction jumpAction = InputActionAsset.FindAction("Player Controls/Jump"); // 가상 코드
문제점:
어떤 InputActionAsset을 검색해야 할지 불명확
프로젝트에 여러 InputActionAsset이 있을 때, 어떤 InputActionAsset에서 검색해야 할지 정의되지 않습니다.
정적 메서드는 객체의 상태에 접근할 수 없으므로, 이 정보가 부족합니다.
다중 InputActionAsset 간 충돌
여러 InputActionAsset에 같은 이름("Player Controls/Jump")의 액션이 있을 경우, 정적 메서드는 어떤 액션을 반환해야 할지 모호해집니다.
즉, 특정 InputActionAsset 객체(inputActions)를 통해 호출해야만 어떤 데이터를 검색할지 알 수 있습니다.
inputActions는 바로 Unity에서 만든 Input Action 자산 파일을 참조하는 변수입니다. 즉, inputActions는 InputActionAsset 타입이고, 이 변수는 Unity의 Input Action 설정 파일과 연결되어 있어야 합니다.
1. InputActionAsset과 FindAction
InputActionAsset은 Unity 에디터에서 만든 Input Actions 자산을 코드에서 참조하는 객체입니다. 이 자산 파일은 Input Actions의 액션 맵과 액션을 설정하는데 사용됩니다. 자산 파일 이름이 아니라, 파일에서 정의된 액션 맵을 코드에서 접근할 수 있도록 합니다.
2. inputActions는 InputActionAsset 자산을 참조해야 한다는 의미
inputActions는 InputActionAsset 자산 파일의 인스턴스를 참조해야 합니다. 이렇게 하면 자산 파일에서 정의된 모든 액션 맵과 액션을 코드에서 사용할 수 있습니다.
예를 들어, Unity 에디터에서 Player Controls라는 이름의 Input Action 자산 파일을 만들었다면, 이 자산을 InputActionAsset 타입의 변수로 참조해야 합니다.public InputActionAsset inputActions; // 에디터에서 연결된 InputActionAsset private InputAction jumpAction; private void Start() { // "Player Controls"라는 액션 맵 안에 있는 "Jump" 액션을 찾기 jumpAction = inputActions.FindAction("Player Controls/Jump"); jumpAction.Enable(); // 액션 활성화 }
두개? 몇개?
한 오브젝트에 여러 Input Action 사용이 가능한가?
Unity는 InputActionAsset 또는 InputActionMap을 원하는 대로 조합해서 사용할 수 있도록 설계되었습니다. 하나의 GameObject에 여러 Input Action을 넣는 방법은 다음 두 가지가 있어요: 방법 1: 두 개 이상의 InputActionAsset을 사용하는 경우 한 오브젝트에 여러 InputActionAsset을 넣으려면, 각각을 변수로 선언하고 연결하면 됩니다. 예를 들어, 아래처럼 두 개의 InputActionAsset을 선언하면 됩니다.
public InputActionAsset playerControl; // 첫 번째 InputActionAsset public InputActionAsset uiControl; // 두 번째 InputActionAsset
그리고 각각의 Asset을 에디터에서 Drag & Drop으로 연결하거나, 코드로 할당할 수 있어요.
한 InputActionAsset 안에 여러 InputActionMap을 사용하는 경우
하나의 InputActionAsset에 여러 InputActionMap을 정의할 수 있습니다.
예를 들어, PlayerControls라는 Asset 안에 다음과 같은 구조를 만들 수 있어요:PlayerControls ├── Player (InputActionMap) │ ├── Move (InputAction) │ ├── Jump (InputAction) ├── UI (InputActionMap) ├── Navigate (InputAction) ├── Submit (InputAction)
이 구조를 활용하면 하나의 InputActionAsset에서 여러 InputActionMap을 사용할 수 있습니다.
예를 들어, 게임플레이 중에는 Player를 활성화하고, UI 상호작용 중에는 UI를 활성화하면 됩니다.InputActionMap playerMap = playerControl.FindActionMap("Player"); InputActionMap uiMap = playerControl.FindActionMap("UI"); playerMap.Enable(); // Player 컨트롤 활성화 uiMap.Disable(); // UI 컨트롤 비활성화
즉,using UnityEngine; using UnityEngine.InputSystem; public class PlayerController : MonoBehaviour { public InputActionAsset inputActions; // Input Actions Asset을 여기서 참조 private InputAction moveAction; private InputAction jumpAction; private void OnEnable() { var playerMap = inputActions.FindActionMap("Player"); // "Player" Action Map을 찾음 moveAction = playerMap.FindAction("Move"); // "Move" Action을 찾음 jumpAction = playerMap.FindAction("Jump"); // "Jump" Action을 찾음 moveAction.Enable(); // Action 활성화 jumpAction.Enable(); // Action 활성화 } private void OnDisable() { moveAction.Disable(); // Action 비활성화 jumpAction.Disable(); // Action 비활성화 } private void Update() { // Action에 대한 입력 처리 Vector2 move = moveAction.ReadValue<Vector2>(); if (jumpAction.triggered) { // 점프 처리 } } }
어차피 저 두 Action Map은 한 파일에 있으니 저렇게 할 수 있다 이말입니다.
같은 파일?
PlayerControls ├── Player (InputActionMap) │ ├── Move (InputAction) │ ├── Jump (InputAction) SecondPlayer ├── Player (InputActionMap) ├── Move (InputAction) ├── Jump (InputAction)
만약 이렇게 두개가 한 오브젝트에 있으면 어떻게 될까요
현재 두 개의 InputActionMap (PlayerControls와 SecondPlayer)이 동일한 오브젝트에 드래그 앤 드롭된 상태에서, 이를 구별하고 FindAction을 사용하려면 각 InputActionMap에 이름을 붙여서 특정 InputActionMap을 찾은 후, 그 안에서 FindAction을 호출해야 합니다.Unity의 새로운 입력 시스템에서 여러 개의 InputActionMap을 사용하고 있을 때, 각 맵을 구별하여 특정 액션을 찾으려면 InputActionMap의 이름을 활용할 수 있습니다.
InputActionMap은 각 액션 맵을 고유하게 식별할 수 있는 이름을 가지고 있으며, 이를 통해 원하는 액션을 찾을 수 있습니다.
'Unity 개인 공부' 카테고리의 다른 글
Unity 개인 공부(2025-01-30) (0) | 2025.01.30 |
---|---|
Unity 개인 공부(2025-01-24) (0) | 2025.01.24 |
Unity 개인 공부(2025-01-22) (2) | 2025.01.22 |
Unity 개인 공부(2025-01-21) (0) | 2025.01.21 |
Unity 개인 공부(2025-01-20) (0) | 2025.01.20 |