Week 04 / Period 01 / Input actions

Input System과 입력 Action

게임은 D키와 오른쪽 화살표를 어떻게 같은 이동으로 이해할까요? 입력 장치와 게임 속 행동을 분리하는 이유를 배우고, Move의 값을 예측하고 실행해 확인합니다.

45분 / 단계별 설정과 설명 / 코드 연결 / 네 번의 실행 비교

빈 방향키 묶음과 아날로그 스틱의 주황색 신호가 중앙의 청록색 2축 이동 행동으로 합쳐져 플레이어에 전달되는 장면
키가 달라도 같은 Move면 코드는 같은 두 숫자를 읽습니다.
이 페이지에서

입력을 게임 속 행동으로 해석합니다

3주차에는 필드에 저장한 속도와 방향으로 오브젝트를 움직였습니다. 이번에는 사용자의 조작에 따라 달라지는 값을 읽습니다. 키를 누르는 일, 입력값을 읽는 일, 그 값으로 오브젝트를 움직이는 일은 각각 어떤 역할을 할까요?

Input System은 키보드·마우스·게임패드의 입력을 게임 코드에서 사용할 수 있게 해 주는 Unity 패키지입니다. 이번 교시에는 설치와 설정 화면을 하나씩 보며 필요한 개념을 배우고, 코드를 연결한 뒤 실행 결과를 해석합니다. 직접 구현하는 개별 실습은 3교시에 진행합니다. 지금은 설정을 따라 완성하는 속도보다 입력이 전달되는 관계를 이해하는 데 집중합니다.

핵심 질문
키가 달라도 같은 행동으로 처리하려면?
학습 방식
설정과 설명 → 코드 연결 → 실행·해석
이전 학습
필드 · 자료형 · 메서드 · Update
핵심 개념
Action · Binding · Vector2
작업 프로젝트
GameEngine1
다음 교시
입력값을 물리 속도로 적용
학습 목표 Input System의 필요성을 설명하고, 키 입력이 Move 값으로 전달되는 과정을 순서대로 설명할 수 있습니다.

Device·Control·Binding·Action을 예시로 구분하고, Value와 Vector2를 선택한 이유를 설명합니다. 마지막에는 Binding을 바꿨을 때 코드와 출력 중 무엇이 달라지는지 예측하고 확인합니다.

  1. 01입력 기능 설치

    Package Manager를 열고 패키지와 입력 활성화의 역할을 구분합니다.

  2. 02Move와 WASD 설정

    에셋·Action·Vector2·Binding을 실제로 설정하는 화면에서 배웁니다.

  3. 03코드를 연결한 뒤 실행

    읽기와 표시 코드를 먼저 이해하고 Player에 연결해 입력값을 봅니다.

  4. 04설정 변경과 결과 비교

    같은 코드에서 키 연결과 참조를 바꾸고 달라진 결과를 해석합니다.

기존 GameEngine1 프로젝트를 사용합니다. 본 수업은 단일 방향 입력을 다루며 대각선 보정 실험은 선택 심화 학습입니다.

기존 캐릭터에 키보드 입력을 연결합니다

3주차에는 Inspector에 저장한 속도로 움직였습니다. 이번에는 키보드 조작을 읽을 기능을 설치하고, 어떤 키를 사용할지 설정합니다. 코드가 그 설정을 어떻게 읽는지 확인한 뒤 처음으로 Play합니다. 수업 화면에서 연결이 하나씩 완성되는 과정을 보며 각 설정의 역할을 이해합니다.

Scene 준비 · 2주차 캐릭터에서 시작하기

4주차에 사용할 Scene을 준비합니다

3주차를 마쳤다면 Week03_Motion에 Mover_A·B·C가 있을 수 있습니다. 이번에는 2주차의 Player가 있는 장면을 열어 4주차용으로 따로 저장합니다. 이미 아래 이름으로 작업 중이라면 그 Scene을 열어 이어서 진행합니다.

  1. 이전 작업 저장 후 Playground 열기

    Play 모드를 종료하고 현재 Scene을 저장합니다. Project의 Assets/Scenes에서 Week02_Playground를 더블클릭합니다. Hierarchy에 Player와 Background가 있는지 확인합니다.

    확인Mover_A·B·C가 보인다면 아직 3주차 Scene입니다. Project에서 Week02_Playground를 다시 확인합니다.
  2. 4주차 Scene으로 별도 저장

    File → Save As를 선택하고 Assets/Scenes/Week04_InputPhysics.unity로 저장합니다. 2교시는 이 Scene을 이어서 사용하고, 3교시에는 별도 Scene으로 저장해 점프 구간을 만듭니다.

    결과Hierarchy의 Scene 이름이 Week04_InputPhysics이고, Project에는 Week02_Playground도 남아 있습니다.
  3. 입력값을 관찰할 Player 확인

    Hierarchy의 Player를 선택하고 왼쪽 삼각형을 펼쳐 자식 DirectionMarker를 확인합니다. Inspector의 Sprite Renderer에 캐릭터 이미지가 연결되어 있어야 합니다. MotionController 등 자동 이동·회전 스크립트가 있다면 컴포넌트 제목 왼쪽 체크박스만 해제합니다. Player와 Sprite Renderer는 켜 둡니다. Ctrl+S로 저장합니다. macOS에서는 Cmd+S를 사용합니다.

    준비 완료Game 탭에 기존 캐릭터가 보이고, Play 모드는 종료되어 있습니다. 이 Player에 입력값 표시 기능을 추가합니다.

시작할 때는 Player와 Sprite Renderer를 켜고 기존 이동 스크립트는 끕니다. 입력 에셋과 InputValueDisplay는 아래 설명을 따라 연결합니다. 이미 물리 컴포넌트가 있는 복습용 Scene이라면 Rigidbody2D의 Simulated를 잠시 해제하고 2교시 전에 다시 켭니다.

다음 단계: 먼저 입력 기능을 프로젝트에 설치합니다.

Input System을 설치하고 활성화합니다

시작 상태: GameEngine1의 Week04_InputPhysics Scene을 열고 Play 모드를 종료합니다. 이미 설치되어 있으면 재설치하지 않고 해당 설정을 확인합니다.

키보드 조작을 코드에서 읽으려면 입력을 처리할 기능이 필요합니다. 먼저 Input System 패키지를 설치합니다. 지금은 어떤 키가 이동을 맡을지 정하기 전입니다.

  1. Package Manager에서 Input System 설치

    패키지는 특정 기능의 코드·설정·도구를 묶어 배포하는 단위입니다. Package Manager는 열려 있는 프로젝트에서 사용할 기능을 관리합니다. Unity Hub에서 Editor를 설치하는 것과는 다른 작업입니다.

    Window → Package Management → Package Manager를 엽니다. 왼쪽에서 Unity Registry를 선택하고 검색창에 Input System을 입력합니다. 검색 결과의 Input System을 클릭해 상세 정보를 엽니다. Install 버튼이 있으면 클릭하고 설치가 끝날 때까지 기다립니다. 이미 설치되어 있다면 버전과 설치 상태만 확인합니다.

    목록에 이름이 보이는 것은 검색 결과이고, Installed가 표시되어야 설치된 상태입니다. GameEngine1에 설치해도 다른 프로젝트에 자동으로 추가되지는 않습니다.

    새 입력 기능을 활성화하고 Editor를 재시작할지 묻는 안내가 나오면 Yes를 선택합니다. 재시작 전 Scene 저장 요청이 나오면 저장합니다.

    결과Package Manager에 Input System이 Installed로 표시됩니다. Unity 6.6 기준 릴리스 버전은 1.20.0입니다.
  2. 입력 처리 방식 선택과 재시작

    패키지 설치는 기능을 추가하는 일이고, Active Input Handling은 사용할 입력 처리 방식을 정하는 설정입니다. New는 새 Input System, Old는 기존 Input Manager, Both는 두 방식의 사용을 뜻합니다.

    Edit → Project Settings → Player → Other Settings에서 Active Input Handling을 찾습니다. Input System Package (New) 또는 Both이면 이번 입력 예제를 실행할 수 있습니다. Input Manager (Old)로 설정되어 있으면 Input System의 입력 처리가 활성화되지 않습니다. 이 항목을 바꾸면 Editor를 재시작해야 적용됩니다.

    완료 기준새 Input System이 활성화되어 Action 에셋을 만들 수 있습니다.
  3. 재시작 뒤 작업 Scene으로 돌아오기

    Editor가 다시 열리면 Hierarchy의 Scene 이름이 Week04_InputPhysics인지 확인합니다. 다른 Scene이 열렸다면 Project의 Assets/Scenes에서 해당 Scene을 더블클릭합니다. Package Manager와 Project Settings 창을 닫고 Project의 Assets를 선택합니다.

    다음 작업 위치Play 모드는 종료되어 있고, Project에서 입력 설정 에셋을 만들 준비가 되었습니다.
설치 직후 확인입력 도구는 준비됐지만, 이동 키는 아직 정하지 않았습니다.

다음에는 이 도구로 GameEngine1의 조작 설정을 저장하는 파일을 만듭니다. 설치만으로 캐릭터가 키 입력에 반응하지는 않습니다.

참고 · Package Manager의 목록과 설치 상태
패키지를 찾는 곳과 설치 상태를 확인하는 곳
화면 항목의미이번 수업에서 할 일
Unity RegistryUnity 레지스트리에서 제공하는 패키지 목록입니다. 설치 여부와 관계없이 표시합니다.Input System을 검색합니다.
All Packages현재 프로젝트에 설치된 패키지를 확인합니다. 이전 버전에서는 In Project 항목으로 설치된 목록을 확인합니다.이 프로젝트에 Input System이 설치되어 있는지 확인합니다.
상세 정보와 버전선택한 패키지의 기능 설명과 버전 정보를 보여 줍니다.패키지 이름과 수업에서 사용하는 버전을 확인합니다.
Install / Update / Remove설치하거나, 설치된 버전을 바꾸거나, 프로젝트에서 제거합니다. 상태에 따라 가능한 버튼이 달라집니다.없으면 Install을 선택하고, 이미 설치되어 있으면 설치 상태만 확인합니다.
My AssetsUnity 계정으로 확보한 Asset Store 패키지를 확인합니다.이번 Input System은 Unity Registry에서 찾습니다.

Package Manager 공식 문서와 패키지 탐색 안내에서 창의 구성을 확인할 수 있습니다.

참고 · Old와 New, 기존 입력 방식과 비교

기존 Legacy Input Manager와 무엇이 다른가요?

예전 Unity 자료에서 보이는 UnityEngine.Input, Input.GetKey, Input.GetAxis는 기존 Input Manager 방식입니다. Legacy는 이전부터 제공되던 입력 체계를 뜻합니다. Input System은 별도 패키지로 제공되는 새 입력 체계이며, 이번 수업에서는 그중 Action을 사용하는 방식을 배웁니다.

Legacy Input Manager와 Input System 비교
비교 기준기존 Input Manager · LegacyInput System · 이번 수업의 Action 방식
설정 위치Project Settings → Input Manager에서 축과 버튼을 설정합니다.Input Actions 에셋에서 Action Map·Action·Binding을 설정합니다.
코드에서 읽기Input.GetKey(KeyCode.D)로 키를 직접 확인하거나 Input.GetAxis("Horizontal")로 이름 붙인 축을 읽습니다.moveAction.action.ReadValue<Vector2>()로 Move에 연결된 현재 방향 값을 읽습니다.
키보드와 게임패드둘 다 지원합니다. 버튼 번호와 조이스틱 축 등을 설정해 입력을 연결합니다.지원 게임패드의 스틱·버튼을 공통 이름으로 다루고, 키보드와 같은 Action에 Binding으로 연결합니다.
조작 설정 변경가상 축을 사용하면 축 설정에서 키를 바꿀 수 있습니다. 키를 코드에 직접 적었다면 코드도 수정합니다.Action을 유지한 채 Binding을 추가하거나 바꿉니다. 실행 중 키 재지정을 위한 API도 제공합니다.
입력 확인 방식보통 Update에서 현재 값이나 버튼 상태를 확인합니다.현재 값을 읽는 방식과 입력 변화에 따라 콜백을 받는 방식을 선택할 수 있습니다.

기존 방식에서도 게임패드와 이름 붙인 축을 사용할 수 있습니다. 이번에 배우는 차이는 Action·Binding·Action Map을 통해 여러 장치와 상황별 입력을 한 구조로 관리하는 방법입니다. Input Manager 공식 문서와 기존 입력 체계에서의 전환 안내에서 두 방식을 비교할 수 있습니다.

방금 확인한 Active Input Handling에서 Old는 기존 방식, New는 Input System, Both는 두 방식을 함께 활성화한다는 뜻입니다. Both를 선택해도 기존 Input.GetAxis 코드가 자동으로 Move Action 코드로 변환되지는 않습니다.

공식 설치 안내 ↗에서 설치와 입력 활성화 절차를 확인할 수 있습니다.

CHECK 01

Input System이 Installed이고 Active Input Handling이 New 또는 Both로 설정되어 있습니다.

다음 단계: PlayerControls 에셋을 만들며 Action Map과 Move를 설정합니다.

Action Map과 Move Action을 생성합니다

시작 상태: 패키지 설치와 입력 활성화를 확인했고 Play 모드는 종료되어 있습니다. Project의 Assets에서 새 입력 설정을 만듭니다.

이제 설정 파일 → 행동 묶음 → 이동 행동 → 값의 형태 순서로 만듭니다. 화면에서 각 항목을 추가할 때 그 항목이 필요한 이유를 함께 확인합니다.

  1. Input Actions 에셋 생성

    설치한 패키지는 입력 기능을 제공하고, Input Actions 에셋은 이 게임의 조작 설정을 저장하는 파일입니다. Project의 Assets에서 우클릭한 뒤 Create → Input Actions를 선택합니다. 이름을 PlayerControls로 입력하고 Enter로 확정합니다. 파일을 더블클릭하면 Action 편집 창이 열립니다. 이미 같은 에셋이 있다면 그 파일을 엽니다.

    결과Project에 PlayerControls.inputactions가 생깁니다.
  2. 왼쪽에서 Player 맵 추가

    Action Map은 함께 활성화하거나 비활성화할 수 있는 Action의 묶음입니다. 왼쪽에 Player 맵이 있으면 그 행을 선택합니다. 없다면 Action Maps 제목 옆 +를 클릭합니다. 새 맵의 이름을 Player로 입력하고 Enter로 확정한 뒤, 그 행을 선택합니다. 이름을 다시 바꾸려면 해당 행을 우클릭해 Rename을 선택합니다.

    이 Player는 행동을 묶는 맵 이름이며 Hierarchy의 캐릭터가 아닙니다. 같은 이름이라고 자동으로 연결되지 않습니다. 나중에 스크립트의 참조로 둘을 연결합니다. Player 맵에는 Move와 Jump를, UI 맵에는 Navigate와 Submit을 묶을 수 있습니다.

    결과왼쪽에 Player 맵이 보입니다.
  3. 가운데에서 Move Action 추가

    Action은 게임이 이해하는 행동 이름입니다. 왼쪽 Player가 선택된 상태에서 가운데 Actions를 봅니다. Action이 없다면 Actions 제목 옆 +를 클릭하고 이름을 Move로 입력한 뒤 Enter로 확정합니다. 기본 Action이 이미 생겼다면 그 행을 우클릭해 Rename으로 이름만 바꿉니다. 이미 Move가 있다면 그대로 선택합니다. Move는 키 이름이 아니라 플레이어가 이동하려 한다는 뜻입니다.

    아직 D나 화살표를 지정하지 않았습니다. 먼저 게임에서 사용할 행동을 정하고 다음 단계에서 키를 연결합니다. 이렇게 하면 코드는 같은 Move를 읽으면서 조작 키만 바꿀 수 있습니다.

    결과Player 아래에 Move가 보입니다.
  4. Move를 선택하고 Value / Vector2 설정

    Vector2는 숫자 두 개를 한 쌍으로 묶은 값입니다. 첫 숫자 x는 가로, 둘째 숫자 y는 세로입니다. 오른쪽 입력은 x의 양수 값으로, 위쪽 입력은 y의 양수 값으로 표현합니다.

    Move 이름이 적힌 행을 클릭합니다. 왼쪽 삼각형은 펼침 버튼이므로 이름 부분을 선택합니다. 오른쪽 Action Properties에서 먼저 Action Type = Value, 이어서 Control Type = Vector2를 선택합니다. Action Type은 입력 처리 방식을, Control Type은 기대하는 값의 형태를 정합니다.

    점프나 확인처럼 버튼의 눌림을 사용할 행동에는 보통 Button을 씁니다. Button도 누르고 있는 상태를 확인할 수 있으므로, “계속 누르면 Value, 한 번 누르면 Button”으로 구분하지 않습니다. 지금은 방향 값을 읽기 위해 Value / Vector2를 선택합니다.

    오른쪽에 Path나 Composite Type만 보이면 Binding을 선택한 상태입니다. 가운데 Move 이름 행을 다시 클릭합니다.

    완료 기준Move가 Value / Vector2입니다. 아직 키는 연결하지 않았습니다.
Action의 동작과 값의 형태는 따로 정합니다
설정질문이번 선택
Action Type어떤 방식으로 입력을 처리할까요?Value: 이동 방향처럼 변하는 값을 다룹니다.
Control Type어떤 형태의 값을 기대하나요?Vector2: 가로와 세로 두 축을 기대합니다.
가로와 세로 계기 세 쌍. 왼쪽은 모두 중앙, 가운데는 가로만 오른쪽, 오른쪽은 세로만 위쪽이며 각 계기 앞의 캐릭터 모형은 같은 자리에 정지해 있음
입력 없음

x = 0, y = 0
두 계기 모두 중앙

D키 입력

x = 1, y = 0
가로 계기만 오른쪽

W키 입력

x = 0, y = 1
세로 계기만 위쪽

가로 계기는 x, 세로 계기는 y입니다. 중앙 눈금은 0이며, 세 장면의 캐릭터는 모두 같은 자리에 있습니다.

계기는 현재 입력값을 비유합니다. 입력값을 읽는 것만으로 캐릭터가 이동하지는 않습니다.

Move의 이름만으로 캐릭터가 움직이지는 않습니다. 지금 만든 것은 이동 의도를 전달할 Action입니다. 어떤 키가 어떤 방향을 만드는지는 다음 Binding 설정에서 정합니다. Actions 공식 문서와 Action Types 공식 문서에서 두 설정의 역할을 확인할 수 있습니다.

설정 저장Save Asset을 클릭해 Player 맵과 Move를 저장합니다.

Scene 저장과 입력 에셋 저장은 별개입니다. 수정한 Action과 Binding은 Action 편집 창의 Save Asset으로 저장합니다.

CHECK 02

왼쪽에 Player, 가운데에 Move가 보이고 Move 이름 행을 선택했을 때 오른쪽이 Value / Vector2입니다. 아직 키는 연결하지 않았습니다.

다음 단계: 키를 연결하며 Binding과 Composite를 확인합니다.

WASD를 연결하며 Binding과 Composite를 이해합니다

시작 상태: Move가 Value / Vector2로 저장되어 있습니다. Play 모드를 종료한 상태에서 Move 아래에 키 연결을 추가합니다.

Move에 어떤 조작을 전달할지 정할 차례입니다. 키를 연결할 때 장치·조작부·연결 규칙의 차이를 함께 봅니다.

  1. Move 아래에 WASD Composite 추가

    Move에는 가로·세로 두 숫자가 필요하지만 키 하나는 눌림과 해제를 전달합니다. 2D Vector Composite는 네 방향의 키를 하나의 Vector2로 합칩니다. 그래서 Action 네 개 대신 한 Move 아래에 네 방향 묶음을 추가합니다.

    가운데 Move 행 오른쪽의 +를 클릭해 Add Up/Down/Left/Right Composite를 선택합니다. Actions 제목 옆의 +는 새 Action을 만드는 버튼입니다. Move 아래 생긴 Composite 묶음을 펼치고, 묶음 이름 행을 우클릭해 Rename으로 WASD라고 지정합니다.

    WASD 부모 행을 선택해 오른쪽 Composite Type이 2D Vector인지 확인합니다. Mode는 기본값 Digital Normalized 그대로 둡니다. 아래 Up·Down·Left·Right는 이 묶음에 속한 네 방향입니다.

    결과Up, Down, Left, Right 네 칸이 하나의 묶음으로 나타납니다.
  2. Up 한 칸에 W 연결

    Binding은 조작부를 Action에 연결하는 규칙입니다. 여기서는 W를 위 방향 역할에 연결합니다. Path의 <Keyboard>/w에서 Keyboard는 장치(Device), w는 장치 안의 조작부(Control)입니다. 파일 경로가 아닙니다.

    가운데 WASD 아래의 Up 행을 클릭합니다. 오른쪽 Binding Properties의 Path 드롭다운을 열고 Listen을 클릭한 뒤 W를 눌렀다 놓습니다. 감지된 W [Keyboard] 항목을 선택해 확정합니다. Path는 <Keyboard>/w에 해당합니다.

    키를 누르기만 하고 창을 닫으면 선택이 완료되지 않을 수 있습니다. 가운데 Up 행에 W [Keyboard]가 표시되는지 확인합니다. 오른쪽에 Mode만 보이면 부모 WASD를 선택한 것이므로 Up을 다시 클릭합니다. Listen은 Binding Path를 선택하는 도구이며 Move의 현재 숫자를 표시하지 않습니다.

    중간 확인Up: W [Keyboard]가 보입니다. 이 한 칸을 확인한 뒤 나머지 키를 연결합니다.
  3. Down·Left·Right도 각각 연결

    Move의 x는 가로, y는 세로 입력입니다. Right는 양수 x, Left는 음수 x, Up은 양수 y, Down은 음수 y를 만듭니다. 어느 키를 어느 방향에 연결하는지가 출력의 부호를 정합니다.

    Down 행을 선택해 Path → Listen → S → 감지된 항목 선택을 반복합니다. 이어서 Left에는 A, Right에는 D를 연결합니다. 매번 가운데에서 수정할 행을 먼저 선택합니다. 같은 Up 행의 Path를 네 번 바꾸는 작업이 아닙니다.

    확인WASD 아래 네 행이 위에서부터 W, S, A, D로 보입니다. 새 Action 네 개를 만들지 않습니다.
  4. 설정 저장 후 다시 열어 확인

    창 오른쪽 위 Save Asset을 클릭합니다. 창을 닫고 Project의 PlayerControls를 다시 더블클릭합니다. Player → Move → WASD를 펼쳐 네 키가 남아 있는지 확인합니다. 방향키는 WASD 입력값을 확인한 뒤에 추가합니다.

    완료 기준Move 아래에 WASD 한 묶음이 저장되어 있고, 네 방향의 키 배치가 아래 표와 일치합니다.
설정한 WASD Binding
선택할 행누를 키연결할 Path
UpW<Keyboard>/w
DownS<Keyboard>/s
LeftA<Keyboard>/a
RightD<Keyboard>/d

Move 행을 선택하면 값의 형식, WASD 부모 행을 선택하면 네 방향을 합치는 방식, Up 같은 자식 행을 선택하면 키 경로가 보입니다. Action과 Binding은 선택하는 행부터 다릅니다. 이번에는 Processors를 추가하지 않고 Mode는 Digital Normalized로 유지합니다.

방금 연결한 네 역할을 짚어 봅니다

Device, Control, Binding, Action은 지금 설정한 경로의 각 역할입니다. 키보드 → D키 → WASD의 Right 연결 → Move 순서로 화면의 항목을 가리켜 봅니다.

01Device

키보드와 게임패드 같은 입력 장치입니다. 사용자의 조작을 입력 신호로 전달하는 장치입니다.

02Control

D키, W키처럼 장치 안의 한 조작부입니다. 설정 창에서 보게 될 Keyboard/d가 이 층입니다.

03Binding

어떤 Control이 어떤 Action에 값을 전달할지 정하는 연결 규칙입니다. 사용할 키와 조작부를 지정하는 설정입니다.

04Action

Move처럼 게임이 이해하는 행동입니다. 입력값 표시 코드는 이 층의 Vector2를 읽습니다.

그림으로 다시 보기 · 키 연결과 Action
키보드와 게임패드가 각각 주황색 케이블 하나로 동일한 수신 장치에 연결된 입체 모형Move ActionDevice · 키보드Device · 게임패드BindingControl · 키Control · 스틱
Device와 Control

키보드 전체는 장치입니다. 개별 키와 게임패드의 스틱은 그 안의 조작부입니다.

Binding과 Action

케이블은 연결 규칙의 비유입니다. 두 장치 모두 같은 Move Action에 입력을 전달합니다.

케이블은 물리적 배선이 아닌 소프트웨어의 연결 규칙을 표현합니다.

설정 창 참고 · 방향키까지 추가한 완성 예시

Input Actions 편집 창. 왼쪽 Action Maps에 Player, 가운데 Actions에 Move와 WASD·Arrows 묶음, 오른쪽에 선택한 Arrows의 Binding Properties가 있습니다.
왼쪽은 맵, 가운데는 Action과 Binding, 오른쪽은 선택한 행의 속성입니다. 캡처는 Arrows를 선택한 상태라 Binding Properties가 보입니다. Value / Vector2는 가운데 Move 이름 행을 클릭하면 나타납니다. 현재는 WASD만 연결하고, Arrows는 실행 03에서 추가합니다.
CHECK 03

Move 아래 WASD 묶음에 Up=W, Down=S, Left=A, Right=D가 보입니다. D는 (1, 0), W는 (0, 1)을 만들도록 연결했습니다. 실제 값은 코드를 붙인 뒤 확인합니다.

다음 단계: 방금 만든 Move를 읽고 표시하는 코드를 연결합니다.

첫 실행 전에 입력을 읽고 표시하는 코드를 연결합니다

시작 상태: WASD가 저장된 Move가 있고 Play 모드는 종료되어 있습니다. 이제 에셋의 입력값을 Game 화면에 표시할 코드를 만듭니다.

입력 설정만으로는 Game 화면에 숫자가 나타나지 않습니다. InputValueDisplay가 Move를 참조하고 활성화한 뒤, 현재 값을 읽어 rawValue에 저장하고 화면에 표시합니다. 위치나 속도를 바꾸는 코드는 넣지 않습니다.

3주차의 필드·메서드·Update를 사용합니다. 전체 코드를 연결한 뒤 대상 지정 → 활성화 → 읽기 → 표시가 어느 줄인지 짚고 첫 실행으로 넘어갑니다.

  1. 스크립트 파일 생성

    Project의 Assets/Scripts를 선택합니다. 폴더가 없으면 Assets에서 우클릭해 Create → Folder로 Scripts를 만듭니다. 폴더 안에서 우클릭해 Create → Scripting → MonoBehaviour Script를 선택하고 이름을 InputValueDisplay로 입력한 뒤 Enter로 확정합니다. 버전에 따라 C# Script로 보일 수 있습니다. 파일 이름과 클래스 이름을 대소문자까지 일치시킵니다. 같은 파일이 있다면 새로 만들지 않고 엽니다.

    결과InputValueDisplay.cs가 생깁니다.
  2. 기본 내용을 아래 완성 코드로 교체

    InputValueDisplay.cs를 더블클릭합니다. 편집기 탭 이름이 InputValueDisplay.cs인지 확인한 뒤 아래 코드의 복사 버튼을 클릭합니다. 편집기로 돌아가 Ctrl+A → Ctrl+V → Ctrl+S로 전체를 교체하고 저장합니다. macOS에서는 Ctrl 대신 Cmd를 사용합니다. 기존 MotionController 파일은 수정하지 않습니다.

    확인파일 첫 줄이 using UnityEngine;이고 클래스 이름은 InputValueDisplay입니다. 기존 클래스 아래에 새 코드를 덧붙이지 않습니다.
  3. Unity로 돌아와 컴파일 확인

    Unity 창을 클릭하고 컴파일이 끝날 때까지 기다립니다. Window → General → Console을 열어 빨간 오류가 0개인지 확인합니다. 오류가 있으면 첫 빨간 항목을 선택해 파일 이름과 내용을 읽습니다. 파일·클래스 이름, 붙여넣은 코드의 누락, Input System 설치를 확인한 뒤 다시 저장합니다.

    다음 단계 조건오류가 0개이면 Hierarchy의 Player에 스크립트를 추가할 수 있습니다. 아직 Play를 시작하지 않습니다.
InputValueDisplay.cs · 완성
using UnityEngine;
using UnityEngine.InputSystem;

public class InputValueDisplay : MonoBehaviour
{
    [SerializeField] private InputActionReference moveAction;

    [SerializeField] private Vector2 rawValue;

    private void OnEnable()
    {
        if (moveAction == null)
        {
            Debug.LogError("InputValueDisplay: Move Action을 연결하세요.", this);
            enabled = false;
            return;
        }

        moveAction.action.Enable();
    }

    private void OnDisable()
    {
        if (moveAction != null)
        {
            moveAction.action.Disable();
        }
    }

    private void Update()
    {
        rawValue = moveAction.action.ReadValue<Vector2>();
    }

    private void OnGUI()
    {
        GUI.Box(new Rect(12f, 12f, 260f, 40f), "raw " + rawValue);
    }
}

방금 넣은 코드를 실행 순서로 읽습니다

  • using UnityEngine.InputSystem;InputActionReference와 Action API를 쓰기 위한 선언입니다. 이 예제는 이 네임스페이스를 가져와 자료형 이름을 짧게 씁니다.
  • InputActionReference moveActionInspector에서 에셋 속 Move의 참조를 지정하는 필드입니다. 키 이름을 코드에 적지 않습니다.
  • OnEnable / OnDisableAction은 활성 상태에서 입력을 처리합니다. 컴포넌트가 활성화될 때 Enable을 호출하고, 비활성화될 때 Disable을 호출합니다. 비활성 Action의 ReadValue는 (0, 0)입니다.
  • ReadValue<Vector2>()Move Action이 지금 만든 값을 읽습니다. 이 코드는 장치를 직접 구분하지 않고 Move의 현재 값을 읽습니다. 곧 실행할 화면에서 raw로 표시될 두 숫자입니다.
  • OnGUIGame 화면에 숫자를 표시합니다. 오브젝트를 움직이지 않습니다. Inspector의 rawValue도 Play 중에 같은 값을 보여 줍니다.

moveAction은 읽을 대상의 참조이고, rawValue는 읽은 결과를 저장하는 값입니다. [SerializeField]로 Inspector에 표시한 Move Action 슬롯에 다음 단계에서 실제 Move를 연결합니다. 필드를 선언하는 것만으로 에셋이 연결되지는 않습니다.

rawValue = moveAction.action.ReadValue<Vector2>();는 오른쪽 메서드를 호출해 반환된 두 숫자를 왼쪽 필드에 저장합니다. <Vector2>는 Move의 Control Type과 맞는 값 형식입니다. Update에서 매 프레임 이 줄을 실행하므로 입력이 바뀌면 저장된 값도 갱신됩니다.

에셋을 저장하는 것과 Action을 활성화하는 것은 다릅니다. 이 코드의 OnEnable()은 컴포넌트가 활성화될 때 Enable()을 호출하고, OnDisable()은 꺼질 때 Disable()을 호출합니다. Start와 달리 OnEnable은 컴포넌트를 다시 켤 때도 호출됩니다.

코드 참고 · null 확인과 표시 부분

Move 참조가 null이면 OnEnable에서 오류를 알리고 enabled = false로 컴포넌트를 끕니다. return;은 현재 메서드를 끝내므로 그 아래의 Enable을 실행하지 않습니다. 마지막 실행에서 이 경우를 정상적인 (0, 0)과 비교합니다.

OnGUI의 GUI.Box와 Rect는 숫자를 담을 상자와 위치·크기를 정합니다. raw는 Action에서 읽은 값에 붙인 표시 이름이며 장치의 가공 전 신호라는 뜻은 아닙니다.

CHECK 04

Console에 빨간 오류가 0개이고, 코드에서 참조·Enable·ReadValue·OnGUI의 역할을 구분할 수 있습니다. 아직 Play를 누르지 않습니다.

다음 단계: Player에 컴포넌트를 추가하고 Move Action 슬롯에 읽을 대상을 지정합니다.

Player에 코드를 추가하고 Move 참조를 연결합니다

시작 상태: InputValueDisplay 코드를 저장하고 컴파일 오류가 없는 상태입니다. Week04_InputPhysics Scene에서 Play를 종료하고 Hierarchy의 Player를 선택합니다.

코드가 완성되었어도 어느 오브젝트에서 실행할지, 어느 Action을 읽을지를 정해야 합니다. Player에 컴포넌트를 추가하고 Move를 연결합니다.

  1. 기존 스프라이트 캐릭터 선택

    Hierarchy에서 2주차에 Sprite Renderer와 캐릭터 이미지를 연결한 Player를 선택합니다. Player의 Sprite와 자식 DirectionMarker는 그대로 사용합니다. 여기에 3주차 MotionController가 있다면 컴포넌트 제목 왼쪽 체크박스의 선택을 해제하고, 자동 이동·회전을 담당하는 다른 스크립트 컴포넌트도 비활성화합니다. Player 오브젝트 자체는 활성 상태로 유지합니다.

    결과기존 캐릭터가 보이고 자동 움직임만 멈춘 상태입니다.
  2. Player에 입력값 표시 스크립트 추가

    Hierarchy에서 Player가 선택되어 Inspector 맨 위에 Player 이름이 보이는지 확인합니다. Project의 InputValueDisplay.cs를 Player의 Inspector 빈 영역으로 드래그합니다. 추가된 Input Value Display 컴포넌트의 체크박스가 켜져 있어야 합니다. 이미 같은 컴포넌트가 있으면 다시 추가하지 않습니다.

    Inspector에 코드 내용만 보인다면 Project의 스크립트 파일을 선택한 상태입니다. Hierarchy의 Player를 다시 선택합니다. Player에는 입력값 표시 컴포넌트 하나만 사용합니다.

    결과Player의 Sprite Renderer와 InputValueDisplay가 함께 있고, InputValueDisplay에 Move Action 슬롯이 보입니다.
  3. Move Action 슬롯에 에셋 속 Move 연결

    이 슬롯은 코드의 InputActionReference moveAction 필드입니다. 스크립트가 읽을 Action을 지정하는 참조이므로 에셋 속 Move를 선택합니다. Input Actions의 Player 맵과 Hierarchy의 Player가 같은 이름이어도 이 연결을 대신해 주지 않습니다.

    Input Value Display 컴포넌트 안의 Move Action 슬롯 오른쪽 원형 선택 버튼을 클릭합니다. 선택 창에서 Move를 검색하고 PlayerControls / Player / Move에 해당하는 항목을 선택합니다. 또는 Project에서 PlayerControls.inputactions를 펼쳐 하위 Move를 이 슬롯으로 드래그합니다. 에셋 파일 전체나 Hierarchy의 Player를 넣는 칸이 아닙니다.

    선택 창을 닫은 뒤 Move Action이 None이 아닌지 확인합니다. 목록에 Move가 없으면 Action 편집 창에서 Save Asset을 클릭하고 Unity의 갱신이 끝난 뒤 선택 창을 다시 엽니다. 칸이 None이면 Play 시 Console에 오류가 나고 컴포넌트가 비활성화됩니다.

    완료 기준Move Action 칸에 Player/Move가 표시됩니다.

참조와 읽은 값은 다른 정보입니다

Move Action 슬롯은 읽을 대상이고 rawValue는 그 대상에서 읽어 저장한 두 숫자입니다. 지금 연결을 마친 뒤 Play하면 OnEnable이 Move를 활성화하고 Update가 현재 값을 읽습니다. None은 읽을 대상이 없는 상태이며 입력값 (0, 0)과 다릅니다.

그림으로 다시 보기 · Move 참조와 rawValue
왼쪽 에셋 속 Move 모듈을 참조하는 오른쪽 컴포넌트. 두 값 타일을 담은 서랍은 컴포넌트 내부에 포함됨입력 에셋Move Action참조컴포넌트rawValue
참조 · 읽을 대상 지정

컴포넌트의 moveAction은 에셋 안의 기존 Move Action을 가리킵니다. Action 자체를 복사하지 않습니다.

값 · 읽은 결과 저장

컴포넌트 내부의 rawValue에 x와 y를 저장합니다. 서랍의 두 타일은 이 두 값을 나타냅니다.

참조 대상은 에셋 안에 있고, 읽은 값은 컴포넌트의 필드에 저장됩니다.

Ctrl+S로 Scene을 저장합니다. 1교시에는 기존 Player·DirectionMarker·Background를 사용하고 입력값만 표시합니다. 2교시에는 같은 캐릭터를 유지하고 기존 Background를 비활성화한 뒤 Ground.png로 바닥을 준비합니다.

CHECK 05

Player의 InputValueDisplay에 PlayerControls / Player / Move가 연결되어 있습니다. Player·Sprite Renderer·InputValueDisplay는 활성, 기존 이동 스크립트는 비활성입니다.

다음 단계: 방금 연결한 코드가 무엇을 보여 줄지 예측한 뒤 처음으로 Play합니다.

코드와 참조를 연결했으니 첫 입력값을 확인합니다

시작 상태: InputValueDisplay와 Move 참조가 연결되어 있고 Play 모드는 종료되어 있습니다. 이제 처음으로 실행해 코드의 읽기·표시 결과를 봅니다.

실행 01 · 숫자는 바뀌는데 캐릭터는 왜 그대로일까요?

실행 전 질문: D를 눌렀을 때 (1, 0)이 보이면 캐릭터가 오른쪽으로 한 칸 이동했다는 뜻일까요? 화면의 숫자와 캐릭터 위치를 따로 봅니다.

  1. 방금 코드를 연결한 장면 실행

    Move 참조까지 연결한 Scene에서 Play를 시작하고 Game 화면 안쪽을 클릭합니다. 모든 키에서 손을 뗀 상태로 raw 상자와 캐릭터를 함께 봅니다.

    관찰raw는 (0, 0)이고 캐릭터는 정지해 있습니다.
  2. D를 누른 뒤 손을 떼기

    D만 누르면 raw가 바뀝니다. 캐릭터의 위치도 바뀌는지 비교합니다. D에서 손을 떼면 숫자가 어떻게 돌아오는지 보고 Play를 종료합니다.

    관찰raw는 (1, 0)이 되지만 위치는 그대로입니다. 손을 떼면 다시 (0, 0)입니다.

결과 해석: 지금 확인한 것은 입력 연결이 작동한다는 사실입니다. Move의 1은 오른쪽 조작의 값이며 거리 1이나 초당 속도 1을 뜻하지 않습니다. 방금 읽은 InputValueDisplay의 실행 순서로 돌아가면 Update는 값을 저장하고 OnGUI는 표시합니다. 위치를 바꾸는 명령이 없으므로 캐릭터가 정지해 있는 것이 정상입니다.

나중에 같은 입력 1에 이동 속도 5를 적용할 수 있지만, 그 계산은 이동 코드의 역할입니다. 이동 속도를 바꿔도 Move의 입력값은 그대로일 수 있습니다. 반대로 입력값이 1이어도 벽에 막히면 위치가 바뀌지 않을 수 있습니다. 입력값, 이동 규칙, 실제 움직임을 구분해야 화면의 결과를 설명할 수 있습니다.

실행 결과를 설정과 코드로 거슬러 올라갑니다

Game 화면의 raw는 하나의 결과지만, 그 앞에는 역할이 다른 단계가 있습니다. D키의 이름은 Binding에 있고, 스크립트에는 Move를 읽는 코드가 있습니다. 키 경로가 코드에 없어도 값을 읽을 수 있는 이유를 아래 순서에서 찾습니다.

D키에서 화면의 숫자까지
단계확인할 대상역할
키와 방향 연결WASD의 Right → DD의 눌림을 오른쪽 방향에 연결합니다.
하나의 값 만들기Move · Value / Vector2이 설정에서 D만 누르면 (1, 0)을 만듭니다.
대상 지정과 활성화moveAction → Enable()읽을 Move를 지정하고 입력 처리를 시작합니다.
현재 값 읽기Update → ReadValue<Vector2>()현재 입력값을 반환받습니다.
저장과 표시rawValue → OnGUI읽은 두 숫자를 필드에 저장하고 Game 화면에 표시합니다.

rawValue는 마지막으로 읽은 값을 보관합니다. 키에서 손을 떼면 다음 Update가 새 값 (0, 0)을 읽어 필드를 덮어씁니다. 필드가 입력 장치와 자동으로 동기화되는 것이 아니라, 코드가 다시 읽어서 저장하는 것입니다.

이 코드에서 Update의 대입 줄을 빼면 값을 갱신하지 못합니다. OnGUI의 표시 줄을 빼면 입력값을 읽더라도 Game 화면에서는 볼 수 없습니다. 아직 위치나 속도에 적용하는 줄은 없으므로, 입력 읽기와 표시가 성공해도 캐릭터는 움직이지 않습니다.

관찰한 값과 코드의 의미 다시 보기

키를 놓으면 (0, 0), D만 누르면 (1, 0)이었습니다. W는 (0, 1)이 될 것으로 예측할 수 있고 다음 실행에서 확인합니다. 이 경우 모두 같은 ReadValue<Vector2>()를 실행합니다. 코드가 D와 W를 각각 검사한 것이 아니라, 에셋의 Binding이 만든 Move 값을 읽은 결과입니다.

Action 값은 Edit 모드에서 갱신되지 않습니다. Binding Path의 Listen은 키 경로를 고르는 도구입니다. 화면에서 입력값을 비교할 때에는 Play 모드와 Game 포커스가 필요합니다.

표시 상자가 없거나 값이 바뀌지 않을 때 확인할 순서

raw 상자 자체가 없다면: Play 모드를 종료하고 Hierarchy의 Player를 선택합니다. Player와 InputValueDisplay가 활성인지, 스크립트가 Player에 붙어 있는지, Console에 빨간 오류가 있는지 순서대로 확인합니다.

Move 연결 오류가 있다면: Console에 InputValueDisplay: Move Action을 연결하세요.가 있으면 참조가 비어 컴포넌트가 비활성화된 것입니다. Play 모드를 종료한 뒤 Move Action 칸에 PlayerControls / Player / Move를 연결합니다. InputValueDisplay 체크박스가 켜져 있는지 확인하고 Scene을 저장한 뒤 다시 Play합니다.

InputActionReference를 찾을 수 없다면 using UnityEngine.InputSystem;이 있는지 확인합니다. 파일 이름과 클래스 이름이 InputValueDisplay로 같은지 확인합니다.

상자는 있는데 계속 (0, 0)이라면: 먼저 Game 화면 안쪽을 클릭하고 D를 다시 누릅니다. 그대로라면 Play를 종료하고 Move가 Value / Vector2인지, WASD의 Right가 D인지, Save Asset을 눌렀는지 확인합니다. 이어서 Active Input Handling이 New 또는 Both인지 확인합니다. 설정을 고친 뒤 다시 Play합니다. Action 편집 창의 Listen은 Path 지정용이라 Play 중 값 확인에 쓰지 않습니다.

숫자와 함께 캐릭터도 움직인다면: Play를 종료하고 MotionController 등 위치·회전을 바꾸는 스크립트를 비활성화합니다. InputValueDisplay에는 이동 코드가 없으므로 다른 컴포넌트가 움직임을 만들고 있는지 확인합니다.

설정과 코드 연결

D의 (1, 0)은 Right Binding에서 만들어지고, ReadValue가 반환한 뒤 rawValue에 저장되어 OnGUI로 보입니다. 이 경로 중 캐릭터의 위치를 바꾸는 단계가 있는지 확인합니다.

다음 단계: 같은 코드에서 키를 오래 누르거나 방향을 바꿨을 때의 값을 비교합니다.

누르는 순간과 누르고 있는 상태는 다릅니다

시작 상태: 첫 실행에서 D의 (1, 0)을 확인하고 Play를 종료했습니다. 같은 코드에서 키를 유지하는 시간과 방향을 바꿔 봅니다.

실행 02 · 방향을 바꾸거나 오래 누르면 값은 어떻게 될까요?

실행 전 질문: D를 약 2초 동안 누르면 Move의 x는 계속 1일까요, 2까지 커질까요? 이번에는 캐릭터의 위치보다 두 숫자의 축·부호·유지 시간을 봅니다.

  1. D를 짧게 누른 경우와 길게 누른 경우 비교

    같은 장면에서 Play를 시작하고 Game 화면을 클릭합니다. D를 짧게 눌렀다 놓은 뒤, 다시 약 2초간 누릅니다. 처음 누른 순간과 계속 누르고 있는 동안의 숫자를 비교합니다.

    관찰누르는 동안 (1, 0)이 유지됩니다. 값이 1, 2, 3으로 누적되지 않습니다.
  2. 한 키씩 바꾸며 축과 부호 비교

    D에서 손을 뗀 뒤 W, A, S를 차례로 누릅니다. 매번 손을 떼어 (0, 0)으로 돌아온 뒤 다음 키를 누릅니다. 한 번에 한 방향만 비교하고 마지막에 Play를 종료합니다.

    관찰W는 y가 양수, A는 x가 음수, S는 y가 음수입니다.
예측·관찰표 · 방향과 유지 시간 비교
조작화면에서 확인한 값해석
키를 놓은 상태(0, 0)현재 방향 입력이 없습니다.
D를 누르고 유지(1, 0)이 유지됨x는 현재 가로 입력이며 누른 시간이 아닙니다.
W만 누름(0, 1)위 방향 입력을 y에 담습니다.
A만 / S만 누름(-1, 0) / (0, -1)음수는 반대 방향을 나타냅니다.

현재 상태는 지금 어떤 조작을 하고 있는지, 변화 시점은 누르기 시작하거나 손을 뗀 때를 뜻합니다. 이동은 누르고 있는 동안 계속 방향이 필요하고, 메뉴 확인 같은 동작은 누른 순간 한 번 처리할 수 있습니다.

D키를 누르고 놓는 시간 순서
시점Move의 현재 값해석
누르기 전(0, 0)방향 입력이 없습니다.
처음 누른 프레임(1, 0)오른쪽 입력이 시작됩니다.
계속 누르는 프레임들(1, 0)같은 상태가 유지됩니다. 누른 시간만큼 값이 커지지 않습니다.
손을 뗀 뒤(0, 0)현재 방향 입력이 사라집니다.

매 프레임 현재 입력값을 조회하는 방식을 폴링(polling)이라고 합니다. 이번에는 Update에서 Move를 읽습니다. 입력 변화에 따라 등록한 메서드를 호출받는 이벤트 방식도 있지만, 이동 입력을 이해하는 데 두 방식을 동시에 구현할 필요는 없습니다.

키는 눌림/해제 두 상태를 갖는 디지털 입력이고, 스틱은 기울인 정도가 연속적으로 달라지는 아날로그 입력입니다. 둘 다 Move의 Vector2로 읽지만 스틱은 중간 세기도 표현합니다.

결과 해석: 입력값은 매번 읽는 순간의 조작 상태입니다. D를 오래 눌러도 입력의 세기가 커지는 것은 아닙니다. 이동 코드가 그 상태를 계속 사용하면 이동 시간이 길어져 거리가 늘어날 수 있습니다. 입력의 크기와 입력을 유지한 시간은 서로 다른 정보입니다.

A의 -1은 오류나 음수 거리가 아니라 왼쪽 입력입니다. W의 y=1도 아직 점프 명령이 아닙니다. 같은 Vector2를 받아도 게임 규칙이 어느 성분을 사용하는지에 따라 동작은 달라집니다. 2교시에는 x를 가로 속도에 사용하고, 3교시에는 별도의 Jump Action으로 점프를 구현합니다.

CHECK 06 · 설명과 연결

“D를 오래 누르면 더 멀리 갈 수 있지만 Move의 x는 계속 1이다.” 입력과 이동 시간을 구분하면 두 설명이 함께 성립합니다.

다음 단계: 입력 코드는 두고 Binding을 바꿔 결과를 비교합니다.

Binding을 추가해 Action의 장점을 확인합니다

시작 상태: 기본 InputValueDisplay 코드와 WASD의 정상 키 배치를 사용합니다. Binding을 바꾸려면 먼저 Play 모드를 종료합니다. 같은 코드에서 설정을 바꾼 전후를 비교합니다.

실행 03 · 키를 추가하거나 바꿔도 코드는 같을까요?

실행 전 질문: D 대신 오른쪽 화살표를 쓰려면 코드에 화살표 검사문을 추가해야 할까요? 이번에는 먼저 입력 방법을 하나 더 연결하고, 이어서 기존 키의 역할을 바꿉니다. 두 경우 모두 InputValueDisplay.cs는 수정하지 않습니다.

  1. Play 종료 후 두 번째 Composite 추가

    Play 모드를 종료하고 Project에서 PlayerControls를 엽니다. Player 맵을 선택한 뒤 Move 행 오른쪽의 +에서 Add Up/Down/Left/Right Composite를 선택합니다. 새 묶음의 이름을 Arrows로 정합니다. 이미 같은 묶음이 있다면 해당 설정을 확인합니다. 기존 WASD 묶음은 그대로 유지합니다.

    Arrows 아래 Up 행을 선택해 Path → Listen으로 위 화살표를 연결합니다. 같은 방식으로 Down=아래, Left=왼쪽, Right=오른쪽을 연결합니다. WASD와 방향키는 서로 다른 Action이 아니라 같은 Move에 입력을 전달하는 두 가지 Binding 구성입니다. Save Asset을 클릭합니다.

    결과Move 아래에 Composite가 두 묶음입니다. 스크립트는 그대로입니다.
  2. 한 번에 한 키씩 눌러 같은 출력인지 확인

    다시 Play 모드를 시작하고 Game 화면 안쪽을 클릭합니다. D를 눌러 값을 읽고 손을 뗀 뒤 오른쪽 화살표를 누릅니다. 두 raw가 같은지 비교합니다. W와 위 화살표도 같은 순서로 확인합니다. 두 키를 동시에 누르지 않고 누르기 → 놓기 → 다른 키 누르기로 비교합니다. 코드는 수정하지 않습니다.

    관찰방향키와 WASD가 같은 두 숫자를 만들고, 코드를 수정하지 않았습니다.
  3. WASD의 Left와 Right 연결만 교환

    Play를 종료합니다. WASD 묶음의 Left Path를 D, Right Path를 A로 바꾸고 Save Asset을 클릭합니다. Arrows 묶음과 Mode는 그대로 둡니다. 다시 Play하고 Game 화면에서 D만 누른 뒤, 손을 떼고 오른쪽 화살표만 누릅니다.

    관찰D는 (-1, 0), 오른쪽 화살표는 여전히 (1, 0)입니다. 같은 Move를 읽어도 키의 연결 규칙에 따라 부호가 달라집니다.
  4. 원래 연결로 복구하고 재확인

    Play를 종료하고 WASD의 Left=A, Right=D로 복구한 뒤 Save Asset을 클릭합니다. 다시 Play해 D와 오른쪽 화살표가 각각 (1, 0)인지 확인하고 Play를 종료합니다. 이후 설명은 이 정상 배치를 기준으로 이어갑니다.

    복구 확인WASD와 Arrows 모두 원래 방향으로 동작합니다. 코드는 처음부터 끝까지 동일합니다.

결과 해석: D키 자체에 오른쪽 이동이라는 의미가 들어 있는 것은 아닙니다. Right에 연결했기 때문에 양수 x를 만들었고, Left에 연결하자 음수 x를 만들었습니다. 반면 오른쪽 화살표는 바꾸지 않은 Arrows의 Right를 사용하므로 결과가 유지됩니다.

방향키 추가는 같은 행동을 실행할 입력 방법을 늘리는 변경이고, 좌우 교환은 기존 키가 맡는 방향을 바꾸는 변경입니다. 두 경우 모두 Move의 Vector2를 읽는 계약은 유지됩니다. 캐릭터의 이동 속도를 바꾸려면 이 Binding이 아니라 다음 교시의 이동 코드를 바꿉니다.

같은 Move의 두 Binding
BindingUpDownLeftRight
WASD / 2D VectorWSAD
Arrows / 2D Vector↑↓←→

두 묶음을 펼쳐 앞에서 본 Input Actions 완성 화면과 비교합니다. Move 아래 WASD와 Arrows가 각각 있고 네 방향의 키가 연결되어 있으면 됩니다. 두 Composite의 Mode는 1교시에서 사용하는 Digital Normalized로 유지합니다. 2교시의 횡스크롤 이동에서는 두 Composite 모두 Digital로 변경합니다.

선택 비교 · 같은 Move에 게임패드 연결

같은 Move로 키보드와 컨트롤러를 함께 사용합니다

Input System이 지원하는 게임패드는 컴퓨터에 연결하면 장치로 인식되며, Move에 스틱 Binding을 설정해 두면 키보드용으로 작성한 같은 코드에서 바로 입력을 읽을 수 있습니다. 예를 들어 지원되는 Xbox 컨트롤러나 PlayStation 컨트롤러의 왼쪽 스틱을 <Gamepad>/leftStick이라는 공통 경로로 연결합니다. 모델별로 이동 스크립트를 따로 작성할 필요가 없습니다.

조작 장치는 달라도 읽는 Action과 코드는 같습니다
입력 장치Move에 설정할 Binding코드에서 읽는 값
키보드 WASD2D Vector Composite · Up=W, Down=S, Left=A, Right=DMove의 Vector2
키보드 방향키같은 Move에 방향키용 2D Vector Composite 추가같은 Move의 Vector2
게임패드 왼쪽 스틱같은 Move에 <Gamepad>/leftStick Binding 추가같은 Move의 Vector2 · 기울인 정도도 포함
장치 연결과 행동 연결게임패드의 입력도 같은 Move Action에서 읽을 수 있습니다.

지원되는 게임패드를 연결하면 Input System이 장치를 인식합니다. Move에 스틱 Binding을 설정하면 기존 코드가 스틱의 입력값을 읽습니다.

이번에 직접 만드는 Move에는 WASD와 방향키만 연결하므로, 게임패드도 사용하려면 스틱 Binding을 한 번 추가해야 합니다. 그 뒤에는 이동 코드를 바꾸지 않고 키보드와 컨트롤러를 번갈아 사용할 수 있습니다.

지원 범위는 컨트롤러 모델·운영체제·연결 방식에 따라 다릅니다. 일부 일반 컨트롤러는 Gamepad 대신 Joystick으로 인식되어 별도 설정이 필요합니다. Gamepads 공식 문서와 지원 장치 표를 참고합니다.

컨트롤러가 있다면 Play 모드를 종료한 상태에서 Move의 + 메뉴로 Add Binding을 선택하고 Path를 <Gamepad>/leftStick으로 지정한 뒤 Save Asset을 클릭합니다. 스틱은 이미 두 축이므로 Composite를 만들 필요가 없습니다. 입력값 확인 실습에서 키보드에서 손을 떼고 스틱을 기울여 값의 방향과 크기를 비교합니다. 컨트롤러가 없어도 위 표로 흐름을 설명할 수 있습니다.

다시 Play 모드를 시작하고 Game 탭을 클릭합니다. 스틱을 조금 기울였을 때와 끝까지 기울였을 때를 비교합니다. 키보드와 같은 코드를 쓰면서 중간 세기가 나온다면 Action이 서로 다른 장치를 같은 형식으로 전달한 것입니다.

CHECK 07

오른쪽 화살표의 raw가 D와 같고, 위 화살표의 raw가 W와 같습니다.

다음 단계: 정상적인 입력 없음과 참조 연결 누락을 비교한 뒤 Scene을 정리합니다.

참조 연결을 확인하고 다음 교시를 준비합니다

시작 상태: WASD의 Left=A, Right=D를 복구했고 방향키도 정상입니다. 마지막으로 읽을 대상이 없는 경우와 정상적으로 읽은 값이 0인 경우를 비교합니다.

실행 04 · None과 (0, 0)은 어떻게 다를까요?

실행 전 질문: Move Action 슬롯을 비우는 것과 키에서 손을 떼는 것은 같은 상태일까요? 이번에는 입력값뿐 아니라 Inspector의 참조, 컴포넌트 체크박스, Console을 함께 봅니다.

  1. 연결된 상태에서 손을 떼기

    InputValueDisplay가 활성이고 Move Action이 PlayerControls / Player / Move인지 확인합니다. Play하고 Game 화면을 클릭한 뒤 D를 눌렀다 놓습니다. 손을 뗀 상태의 표시 상자를 확인한 뒤 Play를 종료합니다.

    관찰상자가 계속 보이고 raw는 (0, 0)으로 돌아옵니다. 읽을 대상은 여전히 연결되어 있습니다.
  2. 참조를 비우고 같은 장면 실행

    Edit 모드에서 Move Action 슬롯의 선택 창을 열어 None으로 바꿉니다. InputValueDisplay는 켜 둡니다. Console의 Clear를 눌러 이전 메시지를 지운 뒤 Play합니다. Game 화면과 Player의 컴포넌트, Console을 차례로 확인합니다.

    관찰연결하라는 오류가 표시되고 InputValueDisplay 체크박스가 꺼집니다. 정상적인 (0, 0) 표시를 얻은 것이 아닙니다.
  3. 참조를 복구하고 정상 실행 확인

    Play를 종료한 뒤 Move Action에 PlayerControls / Player / Move를 다시 연결하고 InputValueDisplay 체크박스를 켭니다. Scene을 저장하고 Console을 Clear한 뒤 다시 Play합니다. Game 화면에서 D의 (1, 0)과 손을 뗀 상태의 (0, 0)을 확인하고 종료합니다.

    복구 확인입력값 표시가 돌아오고 같은 연결 오류가 다시 발생하지 않습니다. 다음 교시에는 참조가 복구된 Scene을 사용합니다.

결과 해석: (0, 0)은 연결된 Action에서 읽을 수 있는 값입니다. None은 읽을 Action의 참조가 없는 상태입니다. 이 예제는 OnEnable에서 null을 발견하면 오류를 알리고 enabled = false와 return;으로 실행을 멈춥니다. 따라서 참조가 없는 상태를 입력이 없는 상태로 해석하면 안 됩니다.

이때 표시 상자도 사라지는 이유는 컴포넌트가 비활성화되어 Update와 OnGUI가 실행되지 않기 때문입니다. 다만 상자가 없다는 현상만으로 원인을 None이라고 단정할 수는 없습니다. 컴포넌트를 직접 꺼도 표시가 사라지므로, 참조·활성 상태·Console의 메시지를 함께 확인해야 합니다.

입력값과 실행 조건 구분
상태보이는 결과확인할 근거
참조 연결 · 키를 놓음raw (0, 0)컴포넌트가 활성이고 키를 누르면 값이 바뀝니다.
참조 None · 컴포넌트를 켜고 Play연결 오류 후 표시가 사라짐OnEnable의 null 검사로 컴포넌트가 비활성화됩니다.
컴포넌트를 직접 비활성화표시가 사라짐값을 읽고 표시하는 코드가 실행되지 않습니다. 참조는 남아 있을 수 있습니다.

정상 설정을 보관하고 이동 수업으로 이어갑니다

참조를 복구한 상태에서 Play를 종료합니다. 2교시 PlayerController가 같은 Move를 활성화하고 비활성화하므로, 입력값 표시 컴포넌트는 아래 순서로 끕니다. 두 컴포넌트가 동일한 Action의 활성화 상태를 동시에 관리하지 않도록 합니다.

  1. Play 종료

    Play 버튼을 클릭해 Play 모드를 종료합니다.

    결과Edit Mode입니다.
  2. 입력값 표시 컴포넌트 비활성화

    Hierarchy에서 Player를 선택합니다. Inspector의 InputValueDisplay 컴포넌트 제목 왼쪽 체크박스의 선택을 해제해 비활성화합니다. Player 오브젝트와 Sprite Renderer는 활성 상태로 유지합니다. 다음 교시는 같은 캐릭터에 물리 이동을 추가합니다.

    결과캐릭터는 계속 보이고 입력값 표시만 비활성화됩니다.
  3. 다음 교시에 이어 쓸 Scene과 입력 설정 저장

    WASD의 Left=A, Right=D와 Move 참조가 복구되어 있는지 확인합니다. Action 편집 창에서 Save Asset을 클릭하고 Unity로 돌아와 Ctrl+S로 Scene을 저장합니다. 저장한 Scene은 Week04_InputPhysics입니다. 실행 예제를 위해 기존 Rigidbody2D의 Simulated를 껐다면 다시 켜고 저장합니다. 2교시에는 같은 Player에 물리 이동을 연결합니다.

    완료 기준Play 모드가 종료되어 있고 Player의 InputValueDisplay만 비활성이며 Scene이 저장되어 있습니다.
개념과 실행 결과 연결하기
항목증거
입력의 역할Move는 조작의 방향이며 위치나 이동 속도가 아닙니다.
설정의 역할Player는 Action Map, Move는 Action, WASD와 방향키는 같은 행동의 Binding입니다.
코드의 역할Enable로 입력을 활성화하고 Update에서 ReadValue로 현재 값을 읽습니다.
예측·관찰D는 (1, 0), W는 (0, 1), 방향키도 같음
정리Play 종료. Player는 활성, InputValueDisplay는 비활성. Week04_InputPhysics Scene과 PlayerControls 에셋 저장
CHECK 08

Player의 모습은 유지되고 InputValueDisplay 컴포넌트만 비활성화되어 있으며 Scene이 저장되어 있습니다.

3교시에서 스스로 적용할 관계행동 정의 → 키 연결 → 코드에서 참조하고 읽기

1교시에는 Move의 방향 값을 관찰했고, 2교시에는 그 값을 좌우 이동과 연결합니다. 3교시 개별 실습에서는 같은 Player 맵에 Jump를 Button으로 추가하고 Space를 연결해 점프를 구현합니다. W의 y=1이 자동으로 점프가 되는 것은 아닙니다.

점프가 반응하지 않을 때는 키의 Binding, Jump 참조, Action 활성화를 먼저 구분해 볼 수 있습니다. 입력이 전달된 뒤 위쪽 속도를 지정하는 처리는 이동 코드에서 구현합니다.

다음 단계: 네 번의 실행을 학습 내용 점검 질문과 연결합니다.

학습 내용 점검

각 질문에서 어느 실행 장면이 근거가 되는지 떠올립니다. 설명을 펼쳐 입력의 값·설정·코드의 역할을 정리합니다. 수업 후에는 답을 가리고 스스로 설명하며 복습할 수 있습니다. 대각선과 Mode는 선택 심화 학습에서 다룹니다.

WASD와 방향키를 같은 Move에 연결하는 이유는 무엇입니까?

키가 달라도 게임 속 의미가 모두 이동이기 때문입니다. 코드는 장치가 아니라 Move의 현재값만 읽습니다.

D만 누르면 (1, 0)이 나옵니다. Player가 오른쪽으로 1만큼 이동했다는 뜻입니까?

아닙니다. 이번 Move에서 (1, 0)은 오른쪽 입력을 뜻합니다. 위치와 속도는 별도 값이며, 실제 이동에는 이 입력을 속도와 물리 처리에 연결하는 코드가 필요합니다.

Action과 Binding의 차이는 무엇입니까?

Action은 Move처럼 게임 속 의미이고, Binding은 W키나 스틱을 그 의미에 연결하는 규칙입니다. Binding Path의 Listen은 그 연결 대상을 찾는 도구이지 Action의 현재 값을 보여 주는 도구가 아닙니다.

입력이 없을 때 Move의 값은 무엇입니까?

(0, 0)입니다. 방향도 크기도 없으므로, 다음 교시의 가로 이동 속도는 0이 됩니다. 공중에서는 입력이 없어도 중력으로 계속 떨어집니다. Action이 비활성화된 상태에서도 ReadValue는 (0, 0)을 반환하므로, 값이 바뀌지 않으면 Action의 활성화 상태와 참조 연결을 먼저 점검합니다.

Move Action의 None과 읽은 값 (0, 0)은 어떻게 다릅니까?

None은 읽을 Action의 참조가 비어 있다는 뜻입니다. (0, 0)은 읽은 값이며, 손을 뗀 상태에서는 정상입니다. 연결 상태를 먼저 구분해야 입력이 없는 것과 설정 누락을 혼동하지 않습니다.

Action Type = Value, Control Type = Vector2인 이유는 무엇입니까?

Value는 이동 방향처럼 변하는 값을 다루는 Action Type입니다. Vector2는 가로와 세로 두 축을 나타내는 값의 형태입니다. 버튼을 오래 누를 수 있는지와는 다른 구분입니다.

선택 심화 학습 · 수업 후 추가 실험

아래는 Vector2의 성질을 알아보는 선택 실험입니다. 횡스크롤 이동 코드에는 이 대각선 보정을 적용하지 않습니다. 2교시에서는 키보드 Composite를 Digital로 바꾸고 x만 사용합니다. 정규 수업 이후 선택적으로 진행합니다. 대각선 길이, Digital Normalized, Mode 실험, Vector2.ClampMagnitude를 다룹니다.

확장 실험용 전체 코드 · 길이 표시 추가

아래 확장 실험을 할 때만 Play 모드를 종료하고 기존 InputValueDisplay.cs의 전체 내용을 이 코드로 바꿉니다. 같은 클래스이므로 별도 파일이나 컴포넌트를 추가하지 않습니다. 컴파일 후 같은 Move 참조를 사용합니다. 2교시 이후라면 PlayerController를 먼저 비활성화하고 InputValueDisplay만 활성화합니다.

magnitude는 벡터의 길이, ClampMagnitude는 최대 길이를 제한하는 계산입니다. ToString("F2")는 길이를 소수점 두 자리로 표시합니다. 이 계산을 추가해야 아래의 raw·clamped 두 줄과 mag를 볼 수 있습니다.

InputValueDisplay.cs · 선택 심화 학습
using UnityEngine;
using UnityEngine.InputSystem;

public class InputValueDisplay : MonoBehaviour
{
    [SerializeField] private InputActionReference moveAction;

    [SerializeField] private Vector2 rawValue;
    [SerializeField] private float rawMagnitude;
    [SerializeField] private Vector2 clampedValue;
    [SerializeField] private float clampedMagnitude;

    private void OnEnable()
    {
        if (moveAction == null)
        {
            Debug.LogError("InputValueDisplay: Move Action을 연결하세요.", this);
            enabled = false;
            return;
        }

        moveAction.action.Enable();
    }

    private void OnDisable()
    {
        if (moveAction != null)
        {
            moveAction.action.Disable();
        }
    }

    private void Update()
    {
        rawValue = moveAction.action.ReadValue<Vector2>();
        rawMagnitude = rawValue.magnitude;
        clampedValue = Vector2.ClampMagnitude(rawValue, 1f);
        clampedMagnitude = clampedValue.magnitude;
    }

    private void OnGUI()
    {
        var text = "raw " + rawValue + "  mag " + rawMagnitude.ToString("F2")
            + "\nclamped " + clampedValue + "  mag " + clampedMagnitude.ToString("F2");
        GUI.Box(new Rect(12f, 12f, 460f, 64f), text);
    }
}

실험 뒤에는 Play 모드를 종료하고 본문의 기본 코드로 되돌립니다. 다음 교시의 이동을 시작할 때는 InputValueDisplay를 비활성화합니다.

clamped 값과 벡터의 길이는 무엇을 의미하나요?

Game 화면 첫 줄의 raw는 Action이 지금 만든 두 숫자입니다. 둘째 줄은 그 값의 길이를 1 이하로 줄인 결과입니다. Vector2.ClampMagnitude는 길이가 1 이하이면 입력을 그대로 두고, 1을 넘을 때만 길이를 1로 줄입니다. 방향은 유지합니다.

value.normalized는 길이가 0에 가깝지 않으면 항상 1로 만듭니다. 스틱을 조금 기울인 입력도 최대 세기가 되므로, 아날로그 강도를 보존하려면 ClampMagnitude를 사용합니다. 기본 Mode의 대각선은 이미 길이 1이라 ClampMagnitude가 숫자를 바꾸지 않을 수 있습니다. Mode를 Digital로 바꿔야 길이 약 1.41이 1로 줄어드는 차이가 보입니다.

대각선 값과 Digital Normalized

2D Vector Composite의 기본 Mode는 Digital Normalized입니다. W+D를 눌러도 기본값에서는 (1, 1)이 아니라 약 (0.71, 0.71)이고 길이는 이미 1입니다. Mode를 Digital로 바꿔야 (1, 1)과 길이 약 1.41이 나옵니다.

조작별 Vector2 값 · 선택 심화 학습
조작XYVector2길이
입력 없음00(0.00, 0.00)0
오른쪽10(1.00, 0.00)1
왼쪽-10(-1.00, 0.00)1
위01(0.00, 1.00)1
아래0-1(0.00, -1.00)1
오른쪽+위, Digital Normalized약 0.71약 0.71(0.71, 0.71)1
오른쪽+위, Digital11(1.00, 1.00)약 1.41
Digital

키보드

눌리지 않음은 0, 눌림은 1입니다. 방향에 따라 부호가 달라집니다. 기본 Mode는 대각선을 길이 1로 맞춥니다.

Analog

게임패드 스틱

기울인 정도를 포함하므로 0과 1 사이의 소수도 나옵니다. 예: (0.42, 0.78)

코드 수정 없는 Binding 실험

이 실험은 수업 후 선택적으로 진행합니다. Play 모드를 종료하고 Player를 선택합니다. 2교시 이후라면 PlayerController 컴포넌트를 먼저 비활성화하고, InputValueDisplay 컴포넌트 제목 왼쪽 체크박스를 선택해 활성화합니다. Player 오브젝트와 Sprite Renderer는 활성 상태로 유지합니다. 입력값 표시 스크립트는 저장한 채 에셋의 설정만 수정합니다. 실행 중인 Action의 설정 변경을 피하기 위해 Play 모드를 종료한 뒤 에셋을 수정합니다.

  1. Mode를 Digital로 변경

    Play 모드를 종료합니다. PlayerControls에서 WASD Composite의 부모 행을 선택합니다. Up 칸이 아니라 묶음 이름 행입니다. 오른쪽 Mode를 Digital Normalized에서 Digital로 바꿉니다. Save Asset을 클릭합니다. InputValueDisplay.cs는 열지 않습니다.

    예상같은 W+D에서 raw는 (1.00, 1.00), 길이는 약 1.41, clamped 길이는 1입니다.
  2. Play 모드에서 결과 비교

    Play 모드를 시작하고 Game 탭을 클릭한 뒤 W+D를 유지합니다. raw와 clamped의 벡터 길이를 비교합니다. D만 누르면 여전히 (1.00, 0.00)입니다. 직선은 Mode와 관계없고, 대각선만 길이가 달라집니다.

    관찰점ClampMagnitude가 하는 일이 이 설정에서만 눈에 띕니다. 기본 Mode에서는 대각선 길이가 이미 1입니다.
  3. Left와 Right를 맞바꿈

    Play 모드를 종료합니다. WASD의 Left Path를 D, Right Path를 A로 바꿉니다. Save Asset을 클릭한 뒤 Play 모드를 시작합니다. 코드는 그대로인데 D를 누르면 raw X가 -1이 됩니다.

    관찰점스크립트를 수정하지 않고도 관찰값이 바뀝니다.
코드 수정 없는 Binding 실험
에셋 상태코드 수정D의 rawW+D raw 길이W+D clamped 길이
기본 Digital Normalized없음(1.00, 0.00)11
Mode = Digital없음(1.00, 0.00)약 1.411
Left/Right 맞바꿈없음(-1.00, 0.00)Mode를 따름1 이하

확인이 끝나면 Play 모드를 종료합니다. Play 모드가 종료된 것을 확인한 뒤 Left=A, Right=D, Mode=Digital Normalized로 되돌리고 Save Asset을 클릭합니다. Player의 InputValueDisplay 컴포넌트만 비활성화합니다. 2교시 이후의 횡스크롤 이동으로 돌아갈 때는 WASD와 방향키 Composite의 Mode를 모두 Digital로 맞추고 Save Asset을 클릭합니다. 이 실험을 위해 PlayerController를 비활성화했다면 해당 컴포넌트를 다시 활성화하고 Ctrl+S로 Scene을 저장합니다. 관찰값이 예측과 다르면 Mode와 Processors에 직접 넣은 항목이 있는지 확인합니다. Processor의 효과는 항목마다 다르므로, 특정 Vector2를 Processor의 결과로 단정하지 않습니다.

선택 심화 학습에서 W+D를 적었다면 기본 Mode Digital Normalized에서 Game 화면에 표시되는 값은 약 (0.71, 0.71)이고 길이는 1입니다.

Unity 공식 문서

용어와 설정은 Unity 6.6 및 해당 Editor용 Input System 문서를 기준으로 정리했습니다. 정확한 규칙을 다시 확인할 때는 아래 공식 문서를 참고합니다.

질문이 남았다면

이해한 부분과 추가 설명이 필요한 부분을 구분합니다. 예: “Move가 Vector2인 것은 이해했습니다. 2D Vector Composite가 네 키를 하나의 값으로 합치는 과정을 에셋 화면과 연결해 설명해 주십시오.”

Next period2교시: Rigidbody2D 기반 이동과 충돌 처리
입력값을 물리 속도로 연결 →