콘텐츠 대표 이미지 - Unity 입력 시스템 패키지로 모든 플랫폼 완벽 제어하기: 크로스 플랫폼 입력 관리의 모든 것

Unity 입력 시스템 패키지로 모든 플랫폼 완벽 제어하기: 크로스 플랫폼 입력 관리의 모든 것

안녕? 오늘은 게임 개발자라면 꼭 알아야 할 Unity의 새로운 입력 시스템 패키지에 대해 함께 알아볼 거야! 🎮 키보드, 마우스부터 모바일 터치, 게임패드까지 모든 입력을 하나의 시스템으로 관리하는 방법을 재미있게 설명해 줄게. 이 글을 다 읽고 나면 너도 크로스 플랫폼 입력 관리의 달인이 될 수 있을 거야! 👑

📚 목차

  1. Unity 입력 시스템의 진화: 왜 새 입력 시스템이 필요할까?
  2. 새 입력 시스템 패키지 설치 및 기본 설정
  3. Input Action Asset 만들기 및 설정하기
  4. 다양한 디바이스 입력 처리하기
  5. 플랫폼별 입력 최적화 전략
  6. 실전 예제: 크로스 플랫폼 캐릭터 컨트롤러 만들기
  7. 입력 시스템 디버깅 및 문제 해결
  8. 성능 최적화 팁과 트릭
  9. 마무리 및 추가 자료

1. Unity 입력 시스템의 진화: 왜 새 입력 시스템이 필요할까? 🚀

Unity로 게임을 개발해 봤다면 Input.GetKey(), Input.GetButton() 같은 함수들을 써봤을 거야. 이 함수들은 Unity의 전통적인 입력 시스템의 일부였지. 근데 이 시스템에는 몇 가지 한계가 있었어.

🔍 기존 입력 시스템의 한계

  1. 다양한 디바이스 지원이 제한적이었어 (특히 새로운 컨트롤러)
  2. 입력 리매핑(사용자 정의 키 설정)이 복잡했지
  3. 여러 플랫폼에서 일관된 코드 작성이 어려웠어
  4. 컨텍스트 기반 입력 처리가 불편했지
  5. 복잡한 제스처나 조합 입력 구현이 까다로웠어

새로운 입력 시스템은 이런 문제들을 해결하기 위해 탄생했어! 이제 하나의 코드로 PC, 콘솔, 모바일, VR 등 모든 플랫폼의 입력을 처리할 수 있게 됐지. 재능넷에서도 많은 개발자들이 이 새로운 시스템을 활용한 게임 개발 노하우를 공유하고 있어. 특히 다양한 플랫폼을 지원해야 하는 개발자들에게 정말 유용한 도구야! 🛠️

기존 입력 시스템 Input.GetKey() Input.GetButton() Input.GetAxis() 제한된 디바이스 지원 플랫폼별 코드 필요 새 입력 시스템 Action-based 입력 다양한 디바이스 지원 간편한 리매핑 컨텍스트 전환 용이 크로스 플랫폼 일관성 🖱️ ⌨️ 🖱️ ⌨️ 🎮 📱 🕹️

새 입력 시스템의 가장 큰 특징은 'Action-based' 접근 방식이야. 이게 무슨 말이냐면, 우리가 "점프하기", "발사하기" 같은 '행동'에 집중하고, 그 행동을 어떤 디바이스의 어떤 버튼이 트리거하는지는 쉽게 설정하고 변경할 수 있게 해준다는 거지. 이렇게 하면 코드는 그대로 두고 입력 매핑만 바꿔서 다양한 플랫폼에 대응할 수 있어! 😎

2. 새 입력 시스템 패키지 설치 및 기본 설정 ⚙️

자, 이제 새 입력 시스템을 설치하고 기본 설정을 해보자! 생각보다 훨씬 쉬울 거야.

📥 패키지 설치하기

  1. Unity 에디터에서 Window > Package Manager 메뉴를 열어줘
  2. "+" 버튼을 누르고 Add package by name 선택
  3. com.unity.inputsystem을 입력하고 'Add' 버튼 클릭
  4. 또는 패키지 목록에서 "Input System"을 검색해서 설치할 수도 있어

💡 참고: Unity 2019.1 이상 버전에서만 새 입력 시스템을 사용할 수 있어. 가능하면 최신 버전의 Unity를 사용하는 걸 추천할게!

패키지를 설치하면 Unity가 재시작을 요청할 거야. 이때 두 가지 옵션이 나타날 수 있어:

  1. Both: 기존 입력 시스템과 새 입력 시스템을 함께 사용 (기존 프로젝트 마이그레이션에 유용)
  2. Input System Package: 새 입력 시스템만 사용 (새 프로젝트에 추천)

새 프로젝트라면 "Input System Package"를 선택하는 게 좋아. 기존 프로젝트를 마이그레이션 중이라면 "Both"를 선택해서 천천히 전환하는 것도 좋은 방법이야! 🔄

Package Manager - Unity Packages Unity Registry Input System Input System Version: 1.5.1 A new input system for Unity. This package provides a new input system which can be used as an alternative to Unity's classic input system in UnityEngine.Input. Install

설치가 완료되면 프로젝트 설정에서 입력 시스템 관련 옵션을 확인해 볼 수 있어. Edit > Project Settings > Input System Package에서 다음과 같은 설정들을 조정할 수 있지:

⚙️ 주요 설정 옵션

  1. Update Mode: 입력 이벤트가 처리되는 시점 (Process Events in Fixed Update, Dynamic Update 등)
  2. Filter Noise on Current: 아날로그 입력의 노이즈 필터링 여부
  3. Compensate for Screen Orientation: 모바일 기기 회전 시 입력 방향 보정 여부
  4. Default Button Press Point: 버튼 입력으로 인식되는 기본 임계값
  5. Default Dead Zone Values: 조이스틱 데드존(무시할 미세 움직임 범위) 설정

🔥 프로 팁: 모바일 게임을 개발한다면 "Compensate for Screen Orientation" 옵션을 켜두는 것이 좋아! 이렇게 하면 기기 회전에 따라 입력 방향이 자동으로 조정되어 사용자 경험이 향상돼.

3. Input Action Asset 만들기 및 설정하기 📝

이제 본격적으로 입력 시스템을 사용해볼 차례야! 새 입력 시스템의 핵심은 Input Action Asset이라는 에셋이야. 이 에셋에서 게임의 모든 입력 액션과 바인딩을 정의하게 될 거야.

🛠️ Input Action Asset 생성하기

  1. 프로젝트 창에서 우클릭 > Create > Input Actions 선택
  2. 생성된 에셋의 이름을 의미 있게 지정해줘 (예: "GameInputs")
  3. 에셋을 더블클릭해서 Input Action 에디터 열기

Input Action Asset은 다음과 같은 계층 구조로 구성돼:

  1. Action Maps: 관련 액션들의 그룹 (예: "Player", "UI", "Vehicle")
  2. Actions: 게임에서 수행할 수 있는 동작들 (예: "Move", "Jump", "Shoot")
  3. Bindings: 액션을 트리거하는 실제 입력들 (예: WASD 키, 게임패드 스틱)
Input Action Asset 구조 Action Maps: "Player" Action: "Move" (Value Type: Vector2) WASD Keys (Keyboard) Left Stick (Gamepad) Action: "Jump" (Value Type: Button) Space Key (Keyboard) South Button (Gamepad) Maps Actions Bindings

자, 이제 간단한 예시로 플레이어 캐릭터를 위한 Input Action Asset을 만들어보자:

🎮 플레이어 입력 설정 예시

  1. Action Map 추가: "Player"
  2. "Player" 맵에 다음 액션들 추가:
    1. "Move" (Value 타입: Vector2) - 캐릭터 이동
    2. "Jump" (Value 타입: Button) - 점프
    3. "Attack" (Value 타입: Button) - 공격
    4. "Interact" (Value 타입: Button) - 상호작용
  3. 각 액션에 적절한 바인딩 추가 (키보드/마우스 및 게임패드)

각 액션에는 다양한 Value 타입을 설정할 수 있어:

  1. Button: 눌림/떼짐 상태를 가진 버튼 입력 (예: 점프, 발사)
  2. Vector2: 2D 벡터 값 (예: 이동 방향, 마우스 위치)
  3. Vector3: 3D 벡터 값 (예: 3D 공간에서의 움직임)
  4. Quaternion: 회전 값 (예: VR 컨트롤러 회전)
  5. Axis: 단일 축 값 (예: 트리거 버튼 압력)

💻 C# 스크립트에서 Input Action Asset 사용하기

Input Action Asset을 설정한 후에는 C# 스크립트에서 이를 사용할 수 있어:


using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    // Input Action Asset 참조
    public InputActionAsset inputActions;
    
    // 개별 액션들
    private InputAction moveAction;
    private InputAction jumpAction;
    
    private void Awake()
    {
        // 액션 맵 가져오기
        var playerActionMap = inputActions.FindActionMap("Player");
        
        // 개별 액션 가져오기
        moveAction = playerActionMap.FindAction("Move");
        jumpAction = playerActionMap.FindAction("Jump");
        
        // 액션에 콜백 함수 등록
        jumpAction.performed += OnJump;
        
        // 액션 맵 활성화
        playerActionMap.Enable();
    }
    
    private void OnJump(InputAction.CallbackContext context)
    {
        // 점프 로직 구현
        Debug.Log("Jump!");
    }
    
    private void Update()
    {
        // Move 액션의 현재 값 읽기
        Vector2 moveInput = moveAction.ReadValue<Vector2>();
        
        // 이동 로직에 사용
        transform.Translate(new Vector3(moveInput.x, 0, moveInput.y) * Time.deltaTime * 5f);
    }
    
    private void OnDestroy()
    {
        // 콜백 해제
        jumpAction.performed -= OnJump;
        
        // 액션 맵 비활성화
        var playerActionMap = inputActions.FindActionMap("Player");
        playerActionMap.Disable();
    }
}
      

💡 중요 팁: Input Action Asset을 C# 클래스로 생성하면 더 편리하게 사용할 수 있어! 에셋 인스펙터에서 "Generate C# Class"를 체크하고 파일 이름을 지정하면 돼. 이렇게 하면 타입 안전성이 보장되고 코드 자동 완성 기능도 사용할 수 있지!

4. 다양한 디바이스 입력 처리하기 🎮📱🖱️

새 입력 시스템의 가장 큰 장점 중 하나는 다양한 입력 디바이스를 쉽게 지원할 수 있다는 거야. 이제 키보드, 마우스, 게임패드, 터치스크린, VR 컨트롤러까지 모두 하나의 시스템으로 관리할 수 있어!

🔌 지원하는 주요 디바이스

  1. 키보드 및 마우스
  2. Xbox, PlayStation, Nintendo Switch 컨트롤러
  3. 모바일 터치스크린 및 가속도계
  4. VR 컨트롤러 (Oculus, Vive, Windows MR 등)
  5. 조이스틱 및 HOTAS 컨트롤러
  6. 사용자 정의 디바이스

하나의 액션에 여러 디바이스의 입력을 바인딩하는 것이 새 입력 시스템의 핵심이야. 예를 들어, "Jump" 액션에 키보드의 스페이스바, Xbox 컨트롤러의 A 버튼, PS 컨트롤러의 X 버튼을 모두 바인딩할 수 있지!

다양한 디바이스 입력 통합 Jump Action ⌨️ Keyboard Space Bar 🎮 Xbox A Button 🎮 PlayStation X Button 📱 Touch Screen Tap 🤸

🔄 디바이스 전환 자동 감지

새 입력 시스템은 사용자가 어떤 디바이스를 사용하고 있는지 자동으로 감지하고 그에 맞게 UI 프롬프트를 업데이트할 수 있어. 이건 크로스 플랫폼 게임에서 정말 유용한 기능이지!


using UnityEngine;
using UnityEngine.InputSystem;

public class DeviceDetector : MonoBehaviour
{
    [SerializeField] private GameObject keyboardPrompts;
    [SerializeField] private GameObject gamepadPrompts;
    [SerializeField] private GameObject touchPrompts;
    
    private void Start()
    {
        // 초기 디바이스 설정
        UpdatePrompts();
        
        // 디바이스 변경 이벤트 구독
        InputSystem.onActionChange += OnInputDeviceChanged;
    }
    
    private void OnInputDeviceChanged(object obj, InputActionChange change)
    {
        if (change == InputActionChange.ActionPerformed)
        {
            UpdatePrompts();
        }
    }
    
    private void UpdatePrompts()
    {
        // 마지막으로 사용된 디바이스 확인
        var lastDevice = InputSystem.GetDevice<InputDevice>();
        
        // 디바이스 타입에 따라 UI 프롬프트 업데이트
        keyboardPrompts.SetActive(lastDevice is Keyboard || lastDevice is Mouse);
        gamepadPrompts.SetActive(lastDevice is Gamepad);
        touchPrompts.SetActive(lastDevice is Touchscreen);
    }
    
    private void OnDestroy()
    {
        // 이벤트 구독 해제
        InputSystem.onActionChange -= OnInputDeviceChanged;
    }
}
      

👆 터치 입력 처리하기

모바일 게임 개발자라면 터치 입력 처리가 중요할 거야. 새 입력 시스템에서는 터치 입력도 쉽게 처리할 수 있어:


// Input Action Asset에서 터치 액션 설정:
// - "PrimaryTouch" (Value 타입: Vector2, Control 타입: Touch > Position)
// - "PrimaryTap" (Value 타입: Button, Control 타입: Touch > Press)

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;

public class TouchController : MonoBehaviour
{
    private InputAction touchPositionAction;
    private InputAction touchPressAction;
    
    private void Awake()
    {
        var inputAsset = GetComponent<PlayerInput>().actions;
        var touchMap = inputAsset.FindActionMap("Touch");
        
        touchPositionAction = touchMap.FindAction("PrimaryTouch");
        touchPressAction = touchMap.FindAction("PrimaryTap");
        
        touchPressAction.performed += OnTap;
    }
    
    private void OnTap(InputAction.CallbackContext context)
    {
        // 탭 위치 가져오기
        Vector2 touchPos = touchPositionAction.ReadValue<Vector2>();
        
        // 터치 위치에서 레이캐스트
        Ray ray = Camera.main.ScreenPointToRay(touchPos);
        if (Physics.Raycast(ray, out RaycastHit hit))
        {
            // 터치한 오브젝트와 상호작용
            Debug.Log($"Tapped on: {hit.collider.gameObject.name}");
        }
    }
    
    private void OnDestroy()
    {
        touchPressAction.performed -= OnTap;
    }
}
      

🔥 프로 팁: 멀티 터치 지원이 필요하다면 EnhancedTouchSupport를 활성화하는 것이 좋아! 이렇게 하면 최대 10개의 동시 터치를 추적할 수 있어.


// 스크립트 시작 부분에 추가
using UnityEngine.InputSystem.EnhancedTouch;

private void Awake()
{
    // 향상된 터치 지원 활성화
    EnhancedTouchSupport.Enable();
}
      

5. 플랫폼별 입력 최적화 전략 🚀

다양한 플랫폼에서 게임을 출시한다면, 각 플랫폼의 특성에 맞게 입력 시스템을 최적화하는 것이 중요해. 재능넷에서도 많은 개발자들이 이런 크로스 플랫폼 최적화 노하우를 공유하고 있지. 여기서는 주요 플랫폼별 최적화 전략을 알아보자!

💻 PC 플랫폼 최적화

  1. 키 리매핑 지원: PC 게이머들은 자신만의 키 설정을 선호해
  2. 마우스 감도 설정: 다양한 DPI 설정을 지원하는 것이 좋아
  3. 게임패드 옵션: PC에서도 게임패드 지원은 필수!

// 키 리매핑 UI 예시 코드
public void RemapKey(string actionName, InputActionMap actionMap)
{
    StartCoroutine(WaitForKeyPress(actionName, actionMap));
}

private IEnumerator WaitForKeyPress(string actionName, InputActionMap actionMap)
{
    // 현재 맵 비활성화
    actionMap.Disable();
    
    // 사용자에게 키 입력 요청 UI 표시
    remappingUI.SetActive(true);
    
    // 키 입력 대기
    bool keyPressed = false;
    InputControl pressedKey = null;
    
    var rebindOperation = actionMap.FindAction(actionName).PerformInteractiveRebinding()
        .WithControlsExcluding("Mouse")
        .OnMatchWaitForAnother(0.1f)
        .OnComplete(operation => {
            pressedKey = operation.selectedControl;
            keyPressed = true;
            operation.Dispose();
        })
        .Start();
    
    while (!keyPressed)
    {
        yield return null;
    }
    
    // UI 업데이트
    remappingUI.SetActive(false);
    UpdateKeyBindingText(actionName, pressedKey.displayName);
    
    // 설정 저장
    SaveKeyBindings();
    
    // 맵 다시 활성화
    actionMap.Enable();
}
        

📱 모바일 플랫폼 최적화

  1. 터치 영역 크기: 손가락 크기를 고려한 충분한 터치 영역 제공
  2. 가상 조이스틱: 이동 컨트롤을 위한 최적화된 가상 조이스틱
  3. 제스처 인식: 스와이프, 핀치 등 다양한 제스처 지원
  4. 화면 방향 대응: 세로/가로 모드 전환 시 입력 처리 최적화

💡 모바일 팁: 가상 조이스틱은 처음 터치한 위치를 중심으로 생성하는 것이 좋아. 이렇게 하면 사용자가 화면의 어디를 터치하든 편하게 조작할 수 있어!

🎮 콘솔 플랫폼 최적화

  1. 컨트롤러 특화 기능: 진동, 모션 컨트롤, 터치패드 등 활용
  2. UI 네비게이션: 컨트롤러로 UI를 쉽게 탐색할 수 있도록 설계
  3. 플랫폼별 버튼 프롬프트: Xbox/PlayStation/Switch 버튼 아이콘 자동 전환
플랫폼별 입력 최적화 💻 PC 키보드 + 마우스 키 리매핑 UI 마우스 감도 설정 단축키 툴팁 게임패드 지원 📱 모바일 터치 + 가속도계 가상 조이스틱 제스처 인식 큰 터치 영역 화면 방향 대응 🎮 콘솔 게임패드 진동 피드백 UI 네비게이션 플랫폼별 버튼 아이콘 특수 컨트롤러 기능

🔄 플랫폼 간 일관된 경험 제공하기

각 플랫폼에 최적화하면서도 게임 경험은 일관되게 유지하는 것이 중요해. 이를 위한 몇 가지 전략을 소개할게:

  1. 입력 추상화: 디바이스 특정 코드를 피하고 액션 기반으로 설계
  2. 자동 감지 및 전환: 사용 중인 디바이스를 감지하고 UI 자동 업데이트
  3. 플랫폼별 기본값 설정: 각 플랫폼에 맞는 기본 설정 제공
  4. 공통 액션 맵 사용: 모든 플랫폼에서 동일한 액션 맵 구조 유지

💻 플랫폼 감지 및 설정 최적화 예시


using UnityEngine;
using UnityEngine.InputSystem;

public class PlatformOptimizer : MonoBehaviour
{
    [SerializeField] private float pcMouseSensitivity = 1.0f;
    [SerializeField] private float consoleLookSensitivity = 0.5f;
    [SerializeField] private float mobileSwipeSensitivity = 0.3f;
    
    [SerializeField] private GameObject pcUI;
    [SerializeField] private GameObject consoleUI;
    [SerializeField] private GameObject mobileUI;
    
    private void Start()
    {
        // 현재 플랫폼 감지 및 최적화
        OptimizeForCurrentPlatform();
        
        // 디바이스 변경 감지
        InputSystem.onDeviceChange += (device, change) => {
            if (change == InputDeviceChange.Added || change == InputDeviceChange.Removed)
            {
                UpdateUIForCurrentDevice();
            }
        };
    }
    
    private void OptimizeForCurrentPlatform()
    {
        // 플랫폼별 설정 최적화
#if UNITY_STANDALONE
        // PC 설정
        SetSensitivity(pcMouseSensitivity);
        ShowUI(pcUI);
#elif UNITY_IOS || UNITY_ANDROID
        // 모바일 설정
        SetSensitivity(mobileSwipeSensitivity);
        ShowUI(mobileUI);
#elif UNITY_PS4 || UNITY_PS5 || UNITY_XBOX_ONE || UNITY_SWITCH
        // 콘솔 설정
        SetSensitivity(consoleLookSensitivity);
        ShowUI(consoleUI);
#endif
    }
    
    private void UpdateUIForCurrentDevice()
    {
        var lastDevice = InputSystem.GetDevice<InputDevice>();
        
        if (lastDevice is Keyboard || lastDevice is Mouse)
        {
            ShowUI(pcUI);
        }
        else if (lastDevice is Gamepad)
        {
            ShowUI(consoleUI);
        }
        else if (lastDevice is Touchscreen)
        {
            ShowUI(mobileUI);
        }
    }
    
    private void SetSensitivity(float value)
    {
        // 감도 설정 적용
        PlayerPrefs.SetFloat("LookSensitivity", value);
    }
    
    private void ShowUI(GameObject uiToShow)
    {
        pcUI.SetActive(uiToShow == pcUI);
        consoleUI.SetActive(uiToShow == consoleUI);
        mobileUI.SetActive(uiToShow == mobileUI);
    }
}
      

🔥 프로 팁: 플랫폼별 설정을 ScriptableObject로 관리하면 에디터에서 쉽게 조정하고 테스트할 수 있어! 이렇게 하면 코드 변경 없이도 각 플랫폼의 설정을 최적화할 수 있지.

6. 실전 예제: 크로스 플랫폼 캐릭터 컨트롤러 만들기 🏃‍♂️

이제 배운 내용을 바탕으로 실제로 작동하는 크로스 플랫폼 캐릭터 컨트롤러를 만들어보자! 이 컨트롤러는 PC, 모바일, 콘솔 등 모든 플랫폼에서 잘 작동할 거야.

🛠️ 1단계: Input Action Asset 설정

먼저 캐릭터 컨트롤을 위한 Input Action Asset을 만들자:

  1. 프로젝트 창에서 우클릭 > Create > Input Actions 선택
  2. 생성된 에셋의 이름을 "PlayerControls"로 지정
  3. 에셋을 더블클릭해서 Input Action 에디터 열기
  4. "Player" Action Map 추가
  5. 다음 액션들 추가:
    1. "Move" (Vector2) - 캐릭터 이동
    2. "Look" (Vector2) - 카메라 회전
    3. "Jump" (Button) - 점프
    4. "Sprint" (Button) - 달리기
    5. "Interact" (Button) - 상호작용
  6. 각 액션에 키보드/마우스, 게임패드, 터치 입력 바인딩 추가
  7. 에셋 인스펙터에서 "Generate C# Class" 체크하고 이름을 "PlayerControls"로 설정
크로스 플랫폼 캐릭터 컨트롤러 🧍 Move WASD / 스틱 / 터치패드 Jump Space / A버튼 / 탭 Sprint Shift / 트리거 / 더블탭 Interact E / X버튼 / 롱프레스 💻 🎮 📱 🕹️ 🥽 모든 플랫폼 지원!

🛠️ 2단계: 캐릭터 컨트롤러 스크립트 작성

이제 생성된 Input Action Asset을 사용하는 캐릭터 컨트롤러 스크립트를 작성해보자:


using UnityEngine;
using UnityEngine.InputSystem;

[RequireComponent(typeof(CharacterController))]
public class CrossPlatformController : MonoBehaviour
{
    // 참조
    private CharacterController controller;
    private PlayerControls playerControls;
    private Camera playerCamera;
    
    // 이동 관련 변수
    private Vector2 moveInput;
    private Vector2 lookInput;
    private bool jumpInput;
    private bool sprintInput;
    
    // 설정
    [Header("Movement Settings")]
    [SerializeField] private float walkSpeed = 5f;
    [SerializeField] private float sprintSpeed = 8f;
    [SerializeField] private float jumpForce = 5f;
    [SerializeField] private float gravity = -9.81f;
    
    [Header("Look Settings")]
    [SerializeField] private float lookSensitivity = 1f;
    [SerializeField] private float lookXLimit = 80f;
    
    // 상태 변수
    private Vector3 moveDirection;
    private Vector3 verticalVelocity;
    private float rotationX = 0;
    private bool isGrounded;
    
    private void Awake()
    {
        // 컴포넌트 참조 가져오기
        controller = GetComponent<CharacterController>();
        playerCamera = Camera.main;
        
        // 입력 액션 초기화
        playerControls = new PlayerControls();
        
        // 입력 콜백 등록
        playerControls.Player.Move.performed += ctx => moveInput = ctx.ReadValue<Vector2>();
        playerControls.Player.Move.canceled += ctx => moveInput = Vector2.zero;
        
        playerControls.Player.Look.performed += ctx => lookInput = ctx.ReadValue<Vector2>();
        playerControls.Player.Look.canceled += ctx => lookInput = Vector2.zero;
        
        playerControls.Player.Jump.performed += ctx => jumpInput = true;
        playerControls.Player.Jump.canceled += ctx => jumpInput = false;
        
        playerControls.Player.Sprint.performed += ctx => sprintInput = true;
        playerControls.Player.Sprint.canceled += ctx => sprintInput = false;
        
        // 마우스 커서 잠금 (PC)
#if UNITY_STANDALONE
        Cursor.lockState = CursorLockMode.Locked;
        Cursor.visible = false;
#endif
    }
    
    private void OnEnable()
    {
        playerControls.Enable();
    }
    
    private void OnDisable()
    {
        playerControls.Disable();
    }
    
    private void Update()
    {
        // 접지 상태 확인
        isGrounded = controller.isGrounded;
        
        // 이동 처리
        HandleMovement();
        
        // 카메라 회전 처리
        HandleLook();
        
        // 점프 처리
        HandleJump();
    }
    
    private void HandleMovement()
    {
        if (isGrounded && verticalVelocity.y < 0)
        {
            verticalVelocity.y = -2f; // 약간의 중력 적용
        }
        
        // 현재 속도 결정 (달리기 여부에 따라)
        float currentSpeed = sprintInput ? sprintSpeed : walkSpeed;
        
        // 이동 방향 계산 (카메라 기준)
        Vector3 forward = playerCamera.transform.forward;
        Vector3 right = playerCamera.transform.right;
        
        forward.y = 0;
        right.y = 0;
        forward.Normalize();
        right.Normalize();
        
        moveDirection = (forward * moveInput.y + right * moveInput.x).normalized;
        
        // 캐릭터 이동
        controller.Move(moveDirection * currentSpeed * Time.deltaTime);
        
        // 중력 적용
        verticalVelocity.y += gravity * Time.deltaTime;
        controller.Move(verticalVelocity * Time.deltaTime);
    }
    
    private void HandleLook()
    {
        // 플랫폼에 따라 감도 조정
#if UNITY_STANDALONE
        float sensitivityMultiplier = 1.0f;
#elif UNITY_IOS || UNITY_ANDROID
        float sensitivityMultiplier = 0.5f;
#else
        float sensitivityMultiplier = 0.7f;
#endif
        
        // 좌우 회전 (캐릭터 전체)
        transform.Rotate(0, lookInput.x * lookSensitivity * sensitivityMultiplier, 0);
        
        // 상하 회전 (카메라만)
        rotationX -= lookInput.y * lookSensitivity * sensitivityMultiplier;
        rotationX = Mathf.Clamp(rotationX, -lookXLimit, lookXLimit);
        playerCamera.transform.localRotation = Quaternion.Euler(rotationX, 0, 0);
    }
    
    private void HandleJump()
    {
        if (jumpInput && isGrounded)
        {
            verticalVelocity.y = Mathf.Sqrt(jumpForce * -2f * gravity);
            jumpInput = false;
        }
    }
}
      

🛠️ 3단계: 모바일 터치 컨트롤 추가

모바일 플랫폼을 위한 가상 조이스틱을 추가해보자:


using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.OnScreen;
using UnityEngine.UI;

public class MobileControls : MonoBehaviour
{
    [SerializeField] private GameObject touchControlsCanvas;
    [SerializeField] private OnScreenStick moveStick;
    [SerializeField] private OnScreenStick lookStick;
    [SerializeField] private Button jumpButton;
    [SerializeField] private Button sprintButton;
    
    private PlayerControls playerControls;
    private PlayerInput playerInput;
    
    private void Awake()
    {
        playerInput = GetComponent<PlayerInput>();
        playerControls = new PlayerControls();
        
        // 플랫폼 감지 및 컨트롤 활성화
#if UNITY_IOS || UNITY_ANDROID
        touchControlsCanvas.SetActive(true);
        SetupTouchControls();
#else
        touchControlsCanvas.SetActive(false);
#endif
    }
    
    private void SetupTouchControls()
    {
        // 이동 스틱 설정
        moveStick.controlPath = "<Gamepad>/leftStick";
        
        // 시점 스틱 설정
        lookStick.controlPath = "<Gamepad>/rightStick";
        
        // 점프 버튼 설정
        jumpButton.onClick.AddListener(() => {
            playerControls.Player.Jump.performed?.Invoke(new InputAction.CallbackContext());
            Invoke("ReleaseJump", 0.1f);
        });
        
        // 달리기 버튼 설정
        sprintButton.onClick.AddListener(() => {
            if (sprintButton.GetComponent<ButtonHoldDetector>().isHolding)
            {
                playerControls.Player.Sprint.performed?.Invoke(new InputAction.CallbackContext());
            }
            else
            {
                playerControls.Player.Sprint.canceled?.Invoke(new InputAction.CallbackContext());
            }
        });
    }
    
    private void ReleaseJump()
    {
        playerControls.Player.Jump.canceled?.Invoke(new InputAction.CallbackContext());
    }
    
    private void OnEnable()
    {
        playerControls.Enable();
    }
    
    private void OnDisable()
    {
        playerControls.Disable();
    }
}

// 버튼 홀드 감지 헬퍼 클래스
public class ButtonHoldDetector : MonoBehaviour
{
    public bool isHolding { get; private set; }
    
    public void OnPointerDown()
    {
        isHolding = true;
    }
    
    public void OnPointerUp()
    {
        isHolding = false;
    }
}
      

🔥 프로 팁: PlayerInput 컴포넌트를 사용하면 위 코드를 더 간단하게 만들 수 있어! 이 컴포넌트는 Input Action Asset을 직접 참조하고, 이벤트를 자동으로 처리해 줘.

🛠️ 4단계: 디바이스 감지 및 UI 업데이트

사용 중인 디바이스에 따라 UI 프롬프트를 업데이트하는 스크립트를 추가하자:


using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.UI;

public class ControlPromptManager : MonoBehaviour
{
    [System.Serializable]
    public class PromptSet
    {
        public string actionName;
        public Sprite keyboardPrompt;
        public Sprite xboxPrompt;
        public Sprite playstationPrompt;
        public Sprite switchPrompt;
        public Sprite touchPrompt;
        public Image targetImage;
    }
    
    [SerializeField] private PromptSet[] prompts;
    
    private void Start()
    {
        // 초기 프롬프트 설정
        UpdatePrompts();
        
        // 디바이스 변경 감지
        InputSystem.onDeviceChange += (device, change) => {
            if (change == InputDeviceChange.Added || change == InputDeviceChange.Removed)
            {
                UpdatePrompts();
            }
        };
    }
    
    private void UpdatePrompts()
    {
        var lastDevice = InputSystem.GetDevice<InputDevice>();
        
        foreach (var prompt in prompts)
        {
            if (lastDevice is Keyboard || lastDevice is Mouse)
            {
                prompt.targetImage.sprite = prompt.keyboardPrompt;
            }
            else if (lastDevice is Gamepad gamepad)
            {
                // 게임패드 제조사 확인
                if (gamepad.displayName.Contains("Xbox") || gamepad.displayName.Contains("XInput"))
                {
                    prompt.targetImage.sprite = prompt.xboxPrompt;
                }
                else if (gamepad.displayName.Contains("PlayStation") || gamepad.displayName.Contains("PS"))
                {
                    prompt.targetImage.sprite = prompt.playstationPrompt;
                }
                else if (gamepad.displayName.Contains("Switch") || gamepad.displayName.Contains("Nintendo"))
                {
                    prompt.targetImage.sprite = prompt.switchPrompt;
                }
                else
                {
                    // 기본값
                    prompt.targetImage.sprite = prompt.xboxPrompt;
                }
            }
            else if (lastDevice is Touchscreen)
            {
                prompt.targetImage.sprite = prompt.touchPrompt;
            }
        }
    }
    
    private void OnDestroy()
    {
        InputSystem.onDeviceChange -= (device, change) => { };
    }
}
      

이렇게 하면 모든 플랫폼에서 잘 작동하는 캐릭터 컨트롤러가 완성돼! 이 컨트롤러는 PC에서는 키보드와 마우스, 콘솔에서는 게임패드, 모바일에서는 터치 컨트롤을 자동으로 지원하게 될 거야. 재능넷에서도 이런 크로스 플랫폼 개발 노하우가 많이 공유되고 있으니 참고해봐! 😊

7. 입력 시스템 디버깅 및 문제 해결 🔍

입력 시스템을 구현하다 보면 여러 가지 문제가 발생할 수 있어. 특히 여러 플랫폼을 지원하는 경우에는 더욱 그렇지. 여기서는 효과적인 디버깅 방법과 자주 발생하는 문제들의 해결책을 알아보자!

🛠️ 디버깅 도구

  1. Input Debugger 창: Window > Analysis > Input Debugger에서 실시간으로 입력 상태 확인 가능
  2. 입력 이벤트 로깅: 콜백 함수에 로그를 추가해 입력 이벤트 추적
  3. 시각적 피드백: 입력에 따른 시각적 피드백을 UI에 표시
  4. InputSystem.GetDevice(): 현재 활성화된 디바이스 확인

💻 입력 디버깅 헬퍼 클래스

다음은 입력 시스템 디버깅에 유용한 헬퍼 클래스야:


using UnityEngine;
using UnityEngine.InputSystem;
using System.Text;
using System.Collections.Generic;

public class InputDebugger : MonoBehaviour
{
    [SerializeField] private InputActionAsset inputActions;
    [SerializeField] private bool logToConsole = true;
    [SerializeField] private TMPro.TextMeshProUGUI debugText;
    
    private Dictionary<string, string> actionStates = new Dictionary<string, string>();
    
    private void Start()
    {
        // 모든 액션 맵과 액션에 디버그 콜백 추가
        foreach (var actionMap in inputActions.actionMaps)
        {
            foreach (var action in actionMap.actions)
            {
                // 초기 상태 기록
                actionStates[action.name] = "Waiting...";
                
                // 콜백 등록
                action.performed += ctx => OnActionEvent(action.name, "Performed", ctx);
                action.started += ctx => OnActionEvent(action.name, "Started", ctx);
                action.canceled += ctx => OnActionEvent(action.name, "Canceled", ctx);
            }
            
            // 액션 맵 활성화
            actionMap.Enable();
        }
    }
    
    private void OnActionEvent(string actionName, string phase, InputAction.CallbackContext context)
    {
        // 값 읽기 시도
        string valueStr = "N/A";
        
        try
        {
            if (context.valueType == typeof(Vector2))
            {
                Vector2 value = context.ReadValue<Vector2>();
                valueStr = $"({value.x:F2}, {value.y:F2})";
            }
            else if (context.valueType == typeof(float))
            {
                float value = context.ReadValue<float>();
                valueStr = value.ToString("F2");
            }
            else if (context.valueType == typeof(bool) || context.valueType == typeof(void))
            {
                valueStr = phase;
            }
        }
        catch
        {
            valueStr = "Error reading value";
        }
        
        // 상태 업데이트
        actionStates[actionName] = $"{phase}: {valueStr}";
        
        // 콘솔에 로그
        if (logToConsole)
        {
            Debug.Log($"[Input] {actionName} - {phase} - Value: {valueStr} - Device: {context.control?.device.name}");
        }
        
        // UI 업데이트
        UpdateDebugText();
    }
    
    private void UpdateDebugText()
    {
        if (debugText != null)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("INPUT DEBUG:");
            sb.AppendLine("------------");
            
            // 현재 활성 디바이스
            var currentDevice = InputSystem.GetDevice<InputDevice>();
            sb.AppendLine($"Active Device: {currentDevice?.displayName ?? "None"}");
            sb.AppendLine();
            
            // 모든 액션 상태
            foreach (var entry in actionStates)
            {
                sb.AppendLine($"{entry.Key}: {entry.Value}");
            }
            
            debugText.text = sb.ToString();
        }
    }
    
    private void Update()
    {
        // 매 프레임 디버그 텍스트 업데이트 (디바이스 변경 감지를 위해)
        UpdateDebugText();
    }
    
    private void OnDestroy()
    {
        // 콜백 해제
        foreach (var actionMap in inputActions.actionMaps)
        {
            foreach (var action in actionMap.actions)
            {
                action.performed -= ctx => { };
                action.started -= ctx => { };
                action.canceled -= ctx => { };
            }
        }
    }
}
      
입력 시스템 디버깅 Input Debugger INPUT DEBUG: ------------ Active Device: Xbox Controller Move: Performed: (0.75, 0.12) Look: Performed: (0.00, 0.00) Jump: Waiting... Sprint: Performed Interact: Canceled Fire: Waiting... Pause: Waiting... Console [Input] Move - Performed - Value: (0.75, 0.12) - Device: Xbox Controller [Input] Sprint - Performed - Value: Performed - Device: Xbox Controller [Input] Interact - Canceled - Value: Canceled - Device: Xbox Controller [Input] Move - Performed - Value: (0.80, 0.15) - Device: Xbox Controller [Input] Move - Performed - Value: (0.82, 0.18) - Device: Xbox Controller [Input] Move - Performed - Value: (0.85, 0.20) - Device: Xbox Controller 실시간 입력 모니터링

🚫 자주 발생하는 문제와 해결책

  1. 입력이 전혀 작동하지 않음

    해결책:

    • Action Map이 활성화되었는지 확인 (actionMap.Enable())
    • 올바른 Action Map을 참조하고 있는지 확인
    • Input Action Asset이 프로젝트에 제대로 포함되었는지 확인
  2. 특정 디바이스에서만 입력이 작동하지 않음

    해결책:

    • 해당 디바이스에 대한 바인딩이 올바르게 설정되었는지 확인
    • 디바이스가 Unity에서 인식되는지 Input Debugger로 확인
    • 플랫폼별 입력 설정 확인 (특히 모바일)
  3. 입력 지연 문제

    해결책:

    • Update Mode 설정 확인 (Project Settings > Input System Package)
    • 프레임 드롭이 발생하는지 확인 (성능 문제일 수 있음)
    • 입력 처리 코드가 무거운 작업을 수행하지 않는지 확인
  4. 여러 디바이스 간 전환 시 문제

    해결책:

    • InputSystem.onDeviceChange 이벤트를 사용해 디바이스 변경 감지
    • 디바이스 변경 시 UI 및 컨트롤 설정 업데이트
    • 여러 디바이스의 동시 입력 처리 로직 확인
  5. Action 값이 예상과 다름

    해결책:

    • Processor 설정 확인 (데드존, 노멀라이제이션 등)
    • 올바른 타입으로 값을 읽고 있는지 확인 (ReadValue<T>())
    • Composite 바인딩 설정이 올바른지 확인

🔥 프로 팁: 디버그 빌드에 입력 시각화 도구를 포함시키는 것이 좋아! 이렇게 하면 QA 테스터나 베타 테스터들이 문제를 발견했을 때 정확한 입력 상태를 보고할 수 있어. 개발 빌드에만 포함되도록 전처리기 지시문을 사용하면 돼!


#if DEVELOPMENT_BUILD || UNITY_EDITOR
    // 디버그 도구 활성화
    inputDebugger.gameObject.SetActive(true);
#else
    // 릴리스 빌드에서는 비활성화
    inputDebugger.gameObject.SetActive(false);
#endif
      

8. 성능 최적화 팁과 트릭 ⚡

입력 시스템은 게임의 반응성에 직접적인 영향을 미치기 때문에 성능 최적화가 매우 중요해. 특히 모바일 기기나 저사양 PC에서는 더욱 그렇지. 여기서는 Unity 입력 시스템의 성능을 최적화하는 방법을 알아보자!

⚡ 일반적인 최적화 팁

  1. 불필요한 액션 비활성화: 현재 사용하지 않는 Action Map은 비활성화하여 처리 오버헤드 줄이기
  2. 이벤트 기반 접근 방식 사용: 매 프레임 폴링보다 이벤트 콜백 사용하기
  3. 입력 처리 빈도 조절: Update Mode 설정으로 입력 처리 빈도 최적화
  4. 가비지 생성 최소화: 콜백에서 불필요한 객체 생성 피하기
  5. 복잡한 조합 입력 제한: 저사양 기기에서는 복잡한 조합 입력 제한하기

💻 성능 최적화 코드 예시

다음은 입력 시스템 성능을 최적화하는 몇 가지 코드 예시야:


using UnityEngine;
using UnityEngine.InputSystem;

public class OptimizedInputManager : MonoBehaviour
{
    [SerializeField] private InputActionAsset inputActions;
    
    // 자주 사용하는 액션 맵 캐싱
    private InputActionMap gameplayMap;
    private InputActionMap menuMap;
    
    // 자주 사용하는 액션 캐싱
    private InputAction moveAction;
    private InputAction lookAction;
    
    // 재사용 가능한 벡터 (가비지 생성 방지)
    private Vector2 moveInput;
    private Vector2 lookInput;
    
    private void Awake()
    {
        // 액션 맵 캐싱
        gameplayMap = inputActions.FindActionMap("Gameplay");
        menuMap = inputActions.FindActionMap("Menu");
        
        // 자주 사용하는 액션 캐싱
        moveAction = gameplayMap.FindAction("Move");
        lookAction = gameplayMap.FindAction("Look");
        
        // 이벤트 기반 콜백 등록 (매 프레임 폴링 대신)
        moveAction.performed += OnMovePerformed;
        moveAction.canceled += OnMoveCanceled;
        
        lookAction.performed += OnLookPerformed;
        lookAction.canceled += OnLookCanceled;
    }
    
    // 게임 상태에 따라 필요한 액션 맵만 활성화
    public void EnterGameplay()
    {
        menuMap.Disable(); // 사용하지 않는 맵 비활성화
        gameplayMap.Enable();
    }
    
    public void EnterMenu()
    {
        gameplayMap.Disable(); // 사용하지 않는 맵 비활성화
        menuMap.Enable();
    }
    
    // 이벤트 기반 콜백 (Update에서 매 프레임 폴링하지 않음)
    private void OnMovePerformed(InputAction.CallbackContext context)
    {
        // 재사용 가능한 벡터에 값 저장 (new Vector2 사용하지 않음)
        moveInput = context.ReadValue<Vector2>();
        
        // 이동 로직 처리
        HandleMovement(moveInput);
    }
    
    private void OnMoveCanceled(InputAction.CallbackContext context)
    {
        moveInput = Vector2.zero;
        HandleMovement(moveInput);
    }
    
    private void OnLookPerformed(InputAction.CallbackContext context)
    {
        lookInput = context.ReadValue<Vector2>();
        HandleLook(lookInput);
    }
    
    private void OnLookCanceled(InputAction.CallbackContext context)
    {
        lookInput = Vector2.zero;
        HandleLook(lookInput);
    }
    
    // 실제 이동 처리 로직
    private void HandleMovement(Vector2 input)
    {
        // 이동 로직 구현
    }
    
    // 실제 시점 처리 로직
    private void HandleLook(Vector2 input)
    {
        // 시점 로직 구현
    }
    
    private void OnDestroy()
    {
        // 콜백 해제
        if (moveAction != null)
        {
            moveAction.performed -= OnMovePerformed;
            moveAction.canceled -= OnMoveCanceled;
        }
        
        if (lookAction != null)
        {
            lookAction.performed -= OnLookPerformed;
            lookAction.canceled -= OnLookCanceled;
        }
    }
}
      
입력 시스템 성능 최적화 최적화 기법 폴링 방식 이벤트 기반 액션 맵 관리 캐싱 모든 최적화 적용 0% 25% 50% 75% 100% 성능 향상 성능 최적화 효과 모든 최적화 적용 시 최대 75% 성능 향상

📱 플랫폼별 성능 최적화

모바일 최적화

  1. 터치 입력 샘플링 레이트 조절: 모든 터치 이벤트를 처리하지 않고 필요한 만큼만 샘플링
  2. 가속도계/자이로스코프 사용 제한: 필요할 때만 활성화
  3. 터치 영역 최적화: 복잡한 제스처 인식보다 간단한 터치 영역 사용

// 모바일 터치 입력 최적화 예시
#if UNITY_IOS || UNITY_ANDROID
    // 터치 샘플링 레이트 조절
    [SerializeField] private float touchSampleRate = 0.05f; // 50ms마다 샘플링
    private float lastTouchSampleTime;
    
    private void Update()
    {
        // 일정 간격으로만 터치 처리
        if (Time.time - lastTouchSampleTime >= touchSampleRate)
        {
            ProcessTouchInput();
            lastTouchSampleTime = Time.time;
        }
    }
    
    private void ProcessTouchInput()
    {
        // 터치 입력 처리 로직
    }
#endif
        

콘솔/PC 최적화

  1. 입력 버퍼링: 빠른 연속 입력을 버퍼링하여 처리
  2. 프레임 독립적 입력: 프레임 레이트에 관계없이 일관된 입력 처리
  3. 하드웨어 특화 기능 최적화: 특정 컨트롤러의 고유 기능 최적화

🔍 고급 최적화 팁

  1. 프로파일링 활용: Unity Profiler를 사용해 입력 시스템의 성능 병목 지점 찾기

    입력 처리 코드에 Profiler.BeginSample("Input Processing")와 Profiler.EndSample()을 사용해 정확한 성능 측정

  2. 입력 우선순위 설정: 중요한 입력은 높은 우선순위로 처리

    예: 일시정지 버튼은 항상 최우선으로 처리, 덜 중요한 입력은 낮은 빈도로 처리

  3. 멀티스레딩 고려: 복잡한 입력 처리는 별도 스레드에서 처리

    주의: Input System의 대부분 API는 메인 스레드에서만 안전하게 호출 가능

  4. 메모리 풀링: 입력 이벤트 처리에 필요한 객체를 미리 풀링하여 가비지 컬렉션 최소화

    특히 모바일에서 중요한 최적화 기법

🔥 프로 팁: 입력 시스템의 Update Mode를 "Process Events in Dynamic Update"로 설정하면 대부분의 경우 최상의 반응성과 성능 밸런스를 얻을 수 있어! 특히 60fps 이상을 목표로 하는 게임에 적합해. 재능넷에서도 많은 개발자들이 이 설정을 추천하고 있어!

9. 마무리 및 추가 자료 📚

지금까지 Unity의 새로운 입력 시스템 패키지를 사용해 크로스 플랫폼 입력을 관리하는 방법에 대해 알아봤어! 이 강력한 시스템을 마스터하면 어떤 플랫폼에서든 일관된 게임 경험을 제공할 수 있을 거야. 😊

📝 요약

  1. Unity의 새 입력 시스템은 다양한 디바이스와 플랫폼을 쉽게 지원할 수 있게 해줘
  2. Action-based 접근 방식으로 입력 로직과 디바이스 바인딩을 분리할 수 있어
  3. Input Action Asset을 통해 에디터에서 시각적으로 입력을 구성할 수 있지
  4. 플랫폼별 최적화를 통해 각 플랫폼에서 최상의 경험을 제공할 수 있어
  5. 디버깅 도구와 성능 최적화 기법으로 안정적인 입력 시스템을 구축할 수 있지

새로운 입력 시스템은 처음에는 약간 복잡해 보일 수 있지만, 익숙해지면 기존 시스템보다 훨씬 강력하고 유연하다는 것을 알게 될 거야. 특히 여러 플랫폼을 지원해야 하는 게임 개발자에게는 정말 큰 도움이 돼!

📚 추가 학습 자료

  1. 공식 문서: Unity 입력 시스템 패키지 공식 문서
  2. 튜토리얼: Unity Learn 플랫폼의 입력 시스템 튜토리얼
  3. 샘플 프로젝트: GitHub에서 제공하는 입력 시스템 샘플
  4. 포럼: Unity 포럼의 입력 시스템 섹션
  5. 재능넷: 재능넷에서 Unity 입력 시스템 관련 노하우와 팁을 공유하는 전문가들의 글
Unity 입력 시스템의 미래 크로스 플랫폼 입력 통합 VR/AR 컨트롤러 모션 캡처 기술 음성 인식 명령 뇌-컴퓨터 인터페이스

Unity의 새 입력 시스템은 계속 발전하고 있어. 앞으로는 더 많은 디바이스와 입력 방식을 지원하게 될 거야. VR/AR 컨트롤러, 모션 캡처, 음성 인식, 심지어 뇌-컴퓨터 인터페이스까지! 게임 개발의 미래는 더욱 다양한 입력 방식을 통합하는 방향으로 나아가고 있어.

이 글이 Unity 입력 시스템을 이해하고 활용하는 데 도움이 됐으면 좋겠어. 만약 더 깊이 있는 내용이나 특정 주제에 대한 질문이 있다면, 재능넷의 개발자 커뮤니티에서 도움을 받을 수 있을 거야. 많은 전문가들이 자신의 경험과 노하우를 공유하고 있으니까! 🚀

🎮 직접 시도해보세요!

이제 배운 내용을 바탕으로 직접 크로스 플랫폼 게임을 개발해보세요! Unity의 새 입력 시스템을 활용하면 PC, 콘솔, 모바일, VR 등 모든 플랫폼에서 최적의 게임 경험을 제공할 수 있습니다.

더 많은 게임 개발 팁과 노하우는 재능넷에서 찾아보세요!

댓글 작성

이 글에 대한 여러분의 생각을 들려주세요

댓글 0
댓글을 불러오는 중입니다.

아직 댓글이 없습니다.