📕학습 개요

유니티 캠프 19일차.

오늘부터 본격적으로 4주차 개인 프로젝트를 시작했다. 튜터님의 강의에서 워낙 깔끔한 프로젝트가 구현되었다 보니 혼자 할 때도 뭔가 완벽하게 구현하고자 하는 욕심이 생기고, 이 때문에 시간이 너무 많이 소모되는 것 같다.

이번 프로젝트는 한 게임 내 다양한 미니게임이 존재하는 일종의 메타버스 프로젝트 이므로, 각종 미니게임 마다 바뀌는 플레이어의 컨트롤 방식을 어떻게 구현할 지 많은 고민을 했다. 전략 패턴으로 구현해보다가 뭔가 너무 과하다 싶어 튜터님의 도움을 받았는데, Input System 을 사용해보라는 조언을 받았다. 내가 왜 그 생각을 못했을까.

여태 유니티의 인풋 시스템을 사용해 본 적은 있지만, 그냥 단순하게 한 종류의 맵핑만 받아와서 해본게 전부, 다양한 맵핑을 자유롭게 변환하며 컨트롤 방식을 바꾸는 용도로 사용해본 건 처음이었다.


📖학습 내용

Input System 활용

1. 기본 설정 및 구조

  • Input Actions Asset (.inputactions): 프로젝트 내에서 입력을 정의하고 관리하는 중앙 에셋.
  • Action Maps: 게임 상태나 미니게임별로 입력 세트를 그룹화 (예: MainMenu, PlayerPlatform, PlayerFlappy). Scene 전환이나 게임 상태 변경 시 활성화/비활성화하여 입력 방식을 전환.
  • Actions: 개별 입력 동작 정의 (예: Move, Jump, Look).
    • Action Type: Value (지속적인 값), Button (눌림/뗌 상태), Pass Through (모든 변경 전달).
    • Control Type: 예상되는 값의 타입 (예: Vector2, Button, Axis, Float).
  • Bindings: 실제 물리적 입력(키, 마우스 버튼, 게임패드 축/버튼 등)을 Action에 연결.
    • 마우스 화면 위치 바인딩: Pointer > Position (Control Type: Vector2).
  • Generate C# Class: Input Actions 에셋 Inspector에서 활성화 시, 에셋 구조를 반영하는 C# 클래스 자동 생성. 코드에서 타입 안전하게 Action 및 Map에 접근 가능. 변경 후에는 반드시 “Apply” 클릭.

2. 스크립트에서의 사용법 (Generated C# Class 기반)

  • 인스턴스화: Awake 등에서 생성된 클래스의 인스턴스 생성.

    private PlayerInputSystem playerInputSystem; // PlayerInputSystem은 생성된 클래스 이름
    
    void Awake()
    {
        playerInputSystem = new PlayerInputSystem();
    }
    
  • Action/Map 참조: 생성된 인스턴스를 통해 Action Map과 Action에 접근.

    private InputActionMap platformMap;
    private InputAction moveAction;
    private InputAction lookAction;
    
    void Awake()
    {
        // ... 인스턴스화 ...
        platformMap = playerInputSystem.PlayerPlatform; // "PlayerPlatform"은 Action Map 이름
        moveAction = platformMap.FindAction("Move");    // "Move"는 Action 이름
        // 또는 직접 접근: moveAction = playerInputSystem.PlayerPlatform.Move;
        lookAction = platformMap.FindAction("Look");
    }
    
  • 활성화/비활성화 (Lifecycle):
    • OnEnable(): 사용할 Action Map 활성화 (map.Enable()), 개별 Action 활성화 (action.Enable()), 이벤트 구독 (+=).
    • OnDisable(): 이벤트 구독 해제 (-=), Action 비활성화 (action.Disable()), Map 비활성화 (map.Disable()). 리소스 누수 방지를 위해 필수!
    • OnDestroy(): Input System 인스턴스 Dispose() (특히 DontDestroyOnLoad 객체).
  • Action Map 전환: 특정 게임 상태나 Scene에 맞는 Map만 활성화하는 함수 구현.

    public void SwitchActionMap(string mapName)
    {
        DisableAllActionMaps(); // 기존 맵 모두 비활성화
        InputActionMap targetMap = playerInputSystem.asset.FindActionMap(mapName);
        targetMap?.Enable(); // 새 맵 활성화
    }
    
    private void DisableAllActionMaps()
    {
        foreach (var map in playerInputSystem.asset.actionMaps) { map.Disable(); }
    }
    
  • 개별 Action 활성화 (action.Enable()):

    • Action Map이 활성화되어도, ReadValue()로 폴링할 Action은 명시적으로 Enable() 해주는 것이 안전하고 명확함 (특히 Update에서 지속적으로 값을 읽을 때).
    • 이벤트 기반 Action은 구독(+=) 시 암시적으로 처리될 수 있지만, 명시적 Enable/Disable이 권장됨.

3. 입력 처리 방식

폴링 (Polling)

  • Update() 또는 FixedUpdate() 등에서 매 프레임 현재 입력 값을 읽어옴.
  • 지속적인 입력(이동, 마우스 조준 등) 처리에 적합.
  • 사용법: action.ReadValue<T>() (T는 Control Type과 일치).
    void Update()
    {
        Vector2 moveInput = moveAction.ReadValue<Vector2>();
        Vector2 mousePos = lookAction.ReadValue<Vector2>();
        // ... 값 사용 ...
    }
    

이벤트 기반 (Callbacks)

  • 입력 상태 변경(시작, 수행, 취소 등) 시점에 등록된 함수(콜백)를 호출.
  • 단발성 입력(점프, 발사, UI 상호작용) 또는 입력 상태 변화 감지에 유용.
  • 사용법:

    • 구독: action.performed += CallbackFunction;, action.canceled += CallbackFunction;, action.started += ... (OnEnable에서).
    • 구독 해제: action.performed -= CallbackFunction; (OnDisable에서).
    • 콜백 함수: InputAction.CallbackContext를 매개변수로 받음.
    • 콜백 내 값 읽기: context.ReadValue<T>().
    void OnEnable() { jumpAction.performed += OnJump; }
    void OnDisable() { jumpAction.performed -= OnJump; }
    
    void OnJump(InputAction.CallbackContext context)
    {
        // 점프 로직 실행
        Debug.Log("Jump performed!");
        // bool buttonState = context.ReadValueAsButton(); // 버튼 상태 읽기
    }
    
    void OnMove(InputAction.CallbackContext context)
    {
        Vector2 input = context.ReadValue<Vector2>(); // Move 값 읽기
        // ... 값 사용 ...
    }
    

🏁오늘 배운 핵심 내용 정리

  1. Action Maps 활용 : 필요에 따라 Action Map 을 만들어 입력 방식을 구분하고, SwitchActionMap() 함수로 필요한 맵만 활성화/비활성화하여 관리한다.
  2. 연속적인 값은 폴링(Polling), 단발성 입력이나 상태 변경 감지는 이벤트로 값을 읽어온다.
  3. 입력 중단 -> canceled 이벤트로 관리 가능
  4. 비활성화(OnDisable) 시 이벤트 구독 해제 필수!

댓글남기기