공용 스크립트 제작기🎈09 - 인풋 시스템 편

Unity 프로젝트의 공용으로 사용할 수 있는 스크립트를 제작하면서 어떻게 만들었는지, 어떤 점에 신경썼는지 설명하는 글입니다.
게임을 만들 때 빼놓을 수 없는 것이 바로 입력 시스템이다. 키보드, 마우스, 게임패드 등 다양한 입력을 통일된 방식으로 처리하고, 입력 설정이 변경될 때마다 코드를 자동으로 생성해주면 편리하지 않을까? Unity의 New Input System을 활용하여 .inputactions 파일만 수정하면 자동으로 코드가 생성되고, 이벤트 구독 방식으로 깔끔하게 사용할 수 있는 입력 시스템을 만들어보자.
핵심은 .inputactions 파일 수정 → 자동 코드 생성 → 이벤트 구독/직접 조회 방식의 간편한 사용이다.
💡예시
간단하게 먼저 사용 예시부터 소개해보자면 다음과 같다.
이벤트 구독 방식
public class PlayerController : MonoBehaviour
{
private void OnEnable()
{
// 이동 입력 이벤트 구독
InputManager.Instance.OnMove += HandleMove;
// 점프 입력 이벤트 구독
InputManager.Instance.OnJumpStarted += HandleJump;
// 공격 입력 이벤트 구독
InputManager.Instance.OnAttackPerformed += HandleAttack;
}
private void OnDisable()
{
// 반드시 구독 해제!
if (InputManager.Instance != null)
{
InputManager.Instance.OnMove -= HandleMove;
InputManager.Instance.OnJumpStarted -= HandleJump;
InputManager.Instance.OnAttackPerformed -= HandleAttack;
}
}
private void HandleMove(Vector2 input)
{
// 이동 처리
transform.Translate(new Vector3(input.x, 0, input.y) * Time.deltaTime * 5f);
}
private void HandleJump()
{
// 점프 처리
Debug.Log("Jump!");
}
private void HandleAttack()
{
// 공격 처리
Debug.Log("Attack!");
}
}
직접 조회 방식
public class PlayerMovement : MonoBehaviour
{
private void Update()
{
// 실시간 입력 값 읽기
Vector2 moveInput = InputManager.Instance.GetMoveInput();
if (moveInput != Vector2.zero)
{
Vector3 movement = new Vector3(moveInput.x, 0, moveInput.y);
transform.Translate(movement * 5f * Time.deltaTime);
}
// 버튼 상태 확인
if (InputManager.Instance.IsJumpPressed())
{
Jump();
}
}
}
입력 제어
public class PauseMenuUI : UIBase
{
public override void OnShow()
{
base.OnShow();
// 플레이어 입력 비활성화, UI 입력 활성화
InputManager.Instance.DisablePlayerInput();
InputManager.Instance.EnableUIInput();
}
public override void OnHide()
{
base.OnHide();
// 플레이어 입력 재활성화, UI 입력 비활성화
InputManager.Instance.EnablePlayerInput();
InputManager.Instance.DisableUIInput();
}
}
📊 클래스 다이어그램
InputManager (싱글톤, partial class)
├─ InputManager.cs (수동 작성 부분)
└─ InputManager.Generated.cs (자동 생성 부분)
├─ 이벤트 선언 (On{ActionName})
├─ 바인딩 메서드 (Bind{MapName}Actions)
└─ Get 메서드 (Get{ActionName}Input)
InputActionCodeGenerator (자동 생성 에디터 툴)
InputActionsPostprocessor (파일 변경 감지 및 자동 재생성)
📁 시스템 아키텍처
핵심 컴포넌트
InputManager.cs (수동 작성 부분)
- 역할: 개발자가 직접 작성하는 핵심 로직
- 주요 기능:
- InputSystem_Actions 인스턴스 생성
- Initialize()에서 BindAllActions() 호출
- Action Map 제어 메서드 제공
- EnablePlayerInput() / DisablePlayerInput()
- EnableUIInput() / DisableUIInput()
- EnableAllInput() / DisableAllInput()
- OnDestroy()에서 정리 작업
InputManager.Generated.cs (자동 생성 부분)
- 역할: .inputactions 파일로부터 자동 생성되는 코드
- 주요 기능:
- 이벤트 선언
- Vector2 타입:
event Action<Vector2> On{ActionName} - Button 타입:
event Action On{ActionName}Started/Performed/Canceled - Vector3 타입:
event Action<Vector3> On{ActionName} - Quaternion 타입:
event Action<Quaternion> On{ActionName}
- Vector2 타입:
- 바인딩 메서드
- Bind{MapName}Actions(): 각 Action Map의 액션 바인딩
- BindAllActions(): 모든 Action Map 바인딩 호출
- Get 메서드
- Vector2:
Vector2 Get{ActionName}Input() - Button:
bool Is{ActionName}Pressed() - Vector3:
Vector3 Get{ActionName}Input() - Quaternion:
Quaternion Get{ActionName}Input()
- Vector2:
- 이벤트 선언
InputActionCodeGenerator (에디터 전용)
- 역할: .inputactions 파일을 파싱하여 C# 코드 생성
- 주요 기능:
- JSON 파싱 (JsonUtility.FromJson)
- InputManager.Generated.cs 생성
- 메뉴 제공:
Tools > Input > Generate Input Manager Code
- 코드 생성 프로세스:
- .inputactions 파일 읽기
- JSON 파싱 → InputActionsData
- Action Map별 이벤트 선언 생성
- Action Map별 바인딩 메서드 생성
- BindAllActions 메서드 생성
- Action Map별 Get 메서드 생성
- 파일 저장 및 AssetDatabase.Refresh()
InputActionsPostprocessor (에디터 전용)
- 역할: .inputactions 파일 변경 감지 및 자동 재생성
- 주요 기능:
- AssetPostprocessor 상속
- OnPostprocessAllAssets()에서 파일 변경 감지
- .inputactions 파일 수정 시 자동으로 코드 재생성
- 동작 방식:
- .inputactions 파일 저장 시 트리거
- InputActionCodeGenerator.GenerateCode() 호출
🔄 데이터 흐름
개발 단계 (에디터)
InputSystem_Actions.inputactions파일 수정- Action Map 추가/수정
- Action 추가/수정
- Binding 설정
↓
- 파일 저장 (Ctrl+S)
↓ - [Unity] InputSystem_Actions.cs 자동 생성
- [InputActionsPostprocessor] 파일 변경 감지
↓ - [InputActionCodeGenerator] JSON 파싱
- Action Map 및 Action 정보 추출
- Action 타입 확인 (Vector2, Button, Vector3, Quaternion)
↓
- [코드 생성] InputManager.Generated.cs 생성:
- 이벤트 선언 (
On{ActionName}) - 바인딩 메서드 (
Bind{MapName}Actions()) - BindAllActions 메서드
- Get 메서드 (
Get{ActionName}Input(),Is{ActionName}Pressed())
↓
- 이벤트 선언 (
- [AssetDatabase.Refresh] Unity 리컴파일
↓ - [완료] InputManager에서 바로 사용 가능
런타임 단계
- [게임 시작] InputManager.Awake() 호출
↓ - [Initialize] InputSystem_Actions 인스턴스 생성
- [BindAllActions] 모든 액션 바인딩:
- BindPlayerActions()
- BindUIActions()
- … (Action Map별 바인딩 메서드 호출)
↓
- [각 바인딩 메서드] InputAction 이벤트 구독
↓ - [EnablePlayerInput] Player Action Map 활성화
↓ - [완료] 입력 시스템 사용 가능
사용자 입력 처리 프로세스
- [플레이어 입력] 키보드/마우스/게임패드 입력
↓ - [Unity Input System] InputAction 트리거
- started / performed / canceled 단계별 호출
↓
- started / performed / canceled 단계별 호출
- [InputManager 바인딩] 이벤트 발행:
OnMove?.Invoke(input)(Vector2)OnJumpStarted?.Invoke()(Button)
↓
- [구독자] 이벤트 핸들러 실행:
HandleMove(Vector2 input)HandleJump()
↓
- [완료] 입력 처리 완료
Action Map 제어 프로세스
- UI 팝업 열림
↓ InputManager.Instance.DisablePlayerInput()inputActions.Player.Disable()호출- Player 입력 비활성화
↓
InputManager.Instance.EnableUIInput()inputActions.UI.Enable()호출- UI 입력 활성화
↓
- UI 팝업 닫힘
↓ InputManager.Instance.EnablePlayerInput()InputManager.Instance.DisableUIInput()
↓- [완료] 원래 입력 상태로 복원
🎯 신경 쓴 부분
자동 재생성 시스템
AssetPostprocessor를 활용한 완전 자동화
public class InputActionsPostprocessor : AssetPostprocessor
{
private static void OnPostprocessAllAssets(
string[] importedAssets, ...)
{
foreach (string assetPath in importedAssets)
{
if (assetPath.EndsWith(INPUT_ACTIONS_FILE))
{
// 파일 완전히 임포트될 때까지 대기 후 재생성
EditorApplication.delayCall += () =>
{
InputActionCodeGenerator.GenerateCode();
};
break;
}
}
}
}
- EditorApplication.delayCall로 Unity의 임포트 프로세스 완료 대기
- 개발자는 파일만 저장하면 자동으로 코드 생성
- 수동 메뉴 실행 불필요
이벤트와 Get 메서드 병행 지원
두 가지 사용 방식 모두 지원하여 유연성 제공
// 이벤트 방식 (권장)
InputManager.Instance.OnMove += HandleMove;
// Get 방식 (실시간 조회)
Vector2 input = InputManager.Instance.GetMoveInput();
- 이벤트 방식: 입력 변경 시에만 호출 (효율적)
- Get 방식: Update()에서 매 프레임 조회 (간편)
- 상황에 맞게 선택 가능
Action Map별 입력 제어
Player, UI 등 Action Map별로 독립적인 활성화/비활성화
// 플레이어 입력만 비활성화
InputManager.Instance.DisablePlayerInput();
// UI 입력만 활성화
InputManager.Instance.EnableUIInput();
// 모든 입력 비활성화 (컷씬 등)
InputManager.Instance.DisableAllInput();
- 상황별로 필요한 입력만 활성화
- UI 팝업 시 플레이어 입력 차단
- 컷씬 재생 시 모든 입력 차단
결론
Unity의 New Input System을 활용하여 자동 코드 생성 기반 입력 시스템을 만들어봤다. .inputactions 파일만 수정하면 코드가 자동으로 생성되고, 이벤트 구독 방식으로 깔끔하게 사용할 수 있어 편리하다. AssetPostprocessor로 완전 자동화한 점이 핵심.