Unity Input System 런타임 키 리바인딩
Unity New Input System은 InputAction.PerformInteractiveRebinding()으로 플레이어가 원하는 키로 조작을 재매핑할 수 있습니다. 리바인딩 결과를 JSON으로 직렬화해 PlayerPrefs에 저장하면 세션 간 설정이 유지됩니다.
1. 기본 리바인딩 흐름
섹션 제목: “1. 기본 리바인딩 흐름”using UnityEngine;using UnityEngine.InputSystem;using TMPro;
public class RebindUI : MonoBehaviour{ [SerializeField] InputActionAsset inputActions; [SerializeField] TMP_Text bindingText; [SerializeField] GameObject waitingOverlay;
private InputActionRebindingExtensions.RebindingOperation _rebindOp;
void Start() { // 현재 바인딩 텍스트 표시 var action = inputActions.FindAction("Player/Jump"); bindingText.text = action.GetBindingDisplayString(); }
public void StartRebind() { var action = inputActions.FindAction("Player/Jump"); action.Disable(); // 리바인딩 중 입력 비활성화
waitingOverlay.SetActive(true);
_rebindOp = action.PerformInteractiveRebinding() .WithControlsExcluding("<Mouse>/position") .WithControlsExcluding("<Mouse>/delta") .OnMatchWaitForAnother(0.1f) // 중복 입력 방지 대기 .OnComplete(op => OnRebindComplete(action, op)) .OnCancel(op => OnRebindCancel(action, op)) .Start(); }
void OnRebindComplete(InputAction action, InputActionRebindingExtensions.RebindingOperation op) { op.Dispose(); action.Enable(); waitingOverlay.SetActive(false); bindingText.text = action.GetBindingDisplayString(); SaveBindings(); }
void OnRebindCancel(InputAction action, InputActionRebindingExtensions.RebindingOperation op) { op.Dispose(); action.Enable(); waitingOverlay.SetActive(false); }
void OnDestroy() => _rebindOp?.Dispose();}2. 특정 바인딩 인덱스 리바인딩
섹션 제목: “2. 특정 바인딩 인덱스 리바인딩”액션에 키보드/게임패드 두 바인딩이 있을 때 각각 독립적으로 리바인딩합니다.
public void StartRebindAtIndex(string actionName, int bindingIndex){ var action = inputActions.FindAction(actionName); action.Disable();
_rebindOp = action .PerformInteractiveRebinding(bindingIndex) .WithControlsExcluding("<Mouse>/position") .OnComplete(op => { op.Dispose(); action.Enable(); SaveBindings(); }) .Start();}3. 바인딩 저장 및 복원
섹션 제목: “3. 바인딩 저장 및 복원”const string BindingsSaveKey = "InputBindings";
void SaveBindings(){ string json = inputActions.SaveBindingOverridesAsJson(); PlayerPrefs.SetString(BindingsSaveKey, json); PlayerPrefs.Save();}
void LoadBindings(){ if (PlayerPrefs.HasKey(BindingsSaveKey)) { string json = PlayerPrefs.GetString(BindingsSaveKey); inputActions.LoadBindingOverridesFromJson(json); }}
public void ResetToDefaults(){ inputActions.RemoveAllBindingOverrides(); PlayerPrefs.DeleteKey(BindingsSaveKey); RefreshAllDisplayTexts();}4. 복합 바인딩(Composite) 리바인딩
섹션 제목: “4. 복합 바인딩(Composite) 리바인딩”WASD 같은 2D Vector Composite의 각 방향을 개별 리바인딩합니다.
public void RebindCompositepart(string actionName, string partName){ var action = inputActions.FindAction(actionName);
// Composite 파트 인덱스 찾기 int bindingIndex = -1; for (int i = 0; i < action.bindings.Count; i++) { if (action.bindings[i].isPartOfComposite && action.bindings[i].name == partName) { bindingIndex = i; break; } }
if (bindingIndex >= 0) StartRebindAtIndex(actionName, bindingIndex);}
// 사용: "Move" 액션의 "up" 파트 리바인딩RebindCompositepart("Player/Move", "up");5. 바인딩 표시 텍스트 갱신
섹션 제목: “5. 바인딩 표시 텍스트 갱신”public void RefreshAllDisplayTexts(){ foreach (var entry in bindingEntries) { var action = inputActions.FindAction(entry.ActionName); entry.Text.text = InputControlPath.ToHumanReadableString( action.bindings[entry.BindingIndex].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice); }}6. 게임패드/키보드 전용 필터링
섹션 제목: “6. 게임패드/키보드 전용 필터링”// 키보드만 허용_rebindOp = action.PerformInteractiveRebinding() .WithBindingGroup("Keyboard") .WithControlsHavingToMatchPath("<Keyboard>") .Start();
// 게임패드만 허용_rebindOp = action.PerformInteractiveRebinding() .WithControlsHavingToMatchPath("<Gamepad>") .Start();PerformInteractiveRebinding의 핵심은 OnComplete에서 Dispose를 호출하고 액션을 다시 Enable하는 것입니다. SaveBindingOverridesAsJson / LoadBindingOverridesFromJson으로 재매핑 상태를 직렬화하면 게임 재시작 후에도 설정이 유지됩니다. WithControlsExcluding으로 마우스 이동축 같은 의도치 않은 입력을 제외하는 것도 필수입니다.