[유니티] input system / input action rebinding

jh Seo·2024년 12월 18일
0

유니티

목록 보기
54/56

개요

How to Rebind Your Controls in Unity (With Icons!) | Input System

위 영상을 보며 유니티의 legacy input이 아닌 새로운 input system을 통해 키 설정 중이였다.
키 rebinding부분을 영상에 나온대로 유니티에서 제공한 sample을 토대로 만들었는 데,
저장/불러오기 과정에서 제대로 로딩이 안 되는 이슈가 있어서 찾아보고 정리한 글이다.

RebindSaveLoad 클래스

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되는 형식이었다.

RebindActionUI 클래스

        /// <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함수 호출하면 된다.

profile
코딩 창고!

0개의 댓글