How to Rebind Your Controls in Unity (With Icons!) | Input System
위 영상을 보며 유니티의 legacy input이 아닌 새로운 input system을 통해 키 설정 중이였다.
키 rebinding부분을 영상에 나온대로 유니티에서 제공한 sample을 토대로 만들었는 데,
저장/불러오기 과정에서 제대로 로딩이 안 되는 이슈가 있어서 찾아보고 정리한 글이다.
public class RebindSaveLoad : MonoBehaviour
{
public InputActionAsset actions;
public void OnEnable()
{
var rebinds = PlayerPrefs.GetString("rebinds");
if (!string.IsNullOrEmpty(rebinds))
{
actions.LoadBindingOverridesFromJson(rebinds);
}
}
public void OnDisable()
{
var rebinds = actions.SaveBindingOverridesAsJson();
PlayerPrefs.SetString("rebinds", rebinds);
}
이 클래스에서 저장과 불러오기를 담당하고 있었다.
함수 구현을 보니 이런 식으로 onenable에서 LoadBindingOverridesFromJson함수를 통해 json파일에서 읽어오고
onDisable에서 json파일로 save되는 형식이었다.
/// <summary>
/// Trigger a refresh of the currently displayed binding.
/// </summary>
public void UpdateBindingDisplay()
{
var displayString = string.Empty;
var deviceLayoutName = default(string);
var controlPath = default(string);
// Get display string from action.
var action = m_Action?.action;
if (action != null)
{
var bindingIndex = action.bindings.IndexOf(x => x.id.ToString() == m_BindingId);
if (bindingIndex != -1)
displayString = action.GetBindingDisplayString(bindingIndex, out deviceLayoutName, out controlPath, displayStringOptions);
}
// Set on label (if any).
if (m_BindingText != null)
m_BindingText.text = displayString;
// Give listeners a chance to configure UI in response.
m_UpdateBindingUIEvent?.Invoke(this, displayString, deviceLayoutName, controlPath);
}
이 클래스에서 rebind action UI를 담당해서 처리해주고 있었다.
그 중 위 UpdateBindingDisplay함수에서 현재 binding 된 키의 UI display를 담당해주고 있었다.
이 함수를 호출해주는 곳을 보니
// When the action system re-resolves bindings, we want to update our UI in response. While this will
// also trigger from changes we made ourselves, it ensures that we react to changes made elsewhere. If
// the user changes keyboard layout, for example, we will get a BoundControlsChanged notification and
// will update our UI to reflect the current keyboard layout.
private static void OnActionChange(object obj, InputActionChange change)
{
if (change != InputActionChange.BoundControlsChanged)
return;
var action = obj as InputAction;
var actionMap = action?.actionMap ?? obj as InputActionMap;
var actionAsset = actionMap?.asset ?? obj as InputActionAsset;
for (var i = 0; i < s_RebindActionUIs.Count; ++i)
{
var component = s_RebindActionUIs[i];
var referencedAction = component.actionReference?.action;
if (referencedAction == null)
continue;
if (referencedAction == action ||
referencedAction.actionMap == actionMap ||
referencedAction.actionMap?.asset == actionAsset)
component.UpdateBindingDisplay();
}
}
// We want the label for the action name to update in edit mode, too, so
// we kick that off from here.
#if UNITY_EDITOR
protected void OnValidate()
{
UpdateActionLabel();
UpdateBindingDisplay();
}
/// <summary>
/// Remove currently applied binding overrides.
/// </summary>
public void ResetToDefault()
{
if (!ResolveActionAndBinding(out var action, out var bindingIndex))
return;
ResetBindings(action,bindingIndex);
//if (action.bindings[bindingIndex].isComposite)
//{
// // It's a composite. Remove overrides from part bindings.
// for (var i = bindingIndex + 1; i < action.bindings.Count && action.bindings[i].isPartOfComposite; ++i)
// action.RemoveBindingOverride(i);
//}
//else
//{
// action.RemoveBindingOverride(bindingIndex);
//}
UpdateBindingDisplay();
}
이렇게 값이 변경되는 부분에만 사용되고 있었다.
따라서 해야할 부분은 json파일에서 키 값 로드 후,
저 함수를 호출해주면 정상적으로 보인다.
public class RebindSaveLoad : MonoBehaviour
{
public InputActionAsset actions;
public GameObject Rebindings;
private List<RebindActionUI> rebindActionUIList= new List<RebindActionUI>();
private void Awake()
{
rebindActionUIList.AddRange(Rebindings.GetComponentsInChildren<RebindActionUI>());
}
public void OnEnable()
{
var rebinds = PlayerPrefs.GetString("rebinds");
if (!string.IsNullOrEmpty(rebinds))
{
actions.LoadBindingOverridesFromJson(rebinds);
//저장한거 불러온후 디스플레이 업데이트
foreach (var action in rebindActionUIList)
action.UpdateBindingDisplay();
}
else
Debug.Log("rebinds not exist!");
이런식으로 RebindActionUI컴퍼넌트를 가진 오브젝트들에서 전부 컴퍼넌트들을 뽑아와서
list로 관리하고 onenable에서 UpdateBindingDisplay함수 호출하면 된다.