Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Feedback InputActionProperty sucks : I've improved it!

Discussion in 'Input System' started by CaseyHofland, Aug 14, 2022.

  1. CaseyHofland

    CaseyHofland

    Joined:
    Mar 18, 2016
    Posts:
    610
    Sorry for the urban diss in the title, it draws attention.

    InputActionProperty: it holds either an InputAction or an InputActionReference. I like the scalability of starting with an InputAction and changing to an InputActionReference when I'm ready, but the editor is too bulky and it is annoying that I still have to call
    action.Enable();
    before I can use it: I want something fire-and-forget that I can use instantly without it clogging up my inspector!

    Bulky.png
    Too Bulky!

    I created my own solution that after having used it for 3 months I can honestly say I will never go back on! It's sleek and having the ability to enable it on start is incredibly useful! It makes the property even more scalable, as I can start with this option enabled, and use a custom way of enabling / disabling input once I feel comfortable to do so.

    Sleek.png

    Collapsed.png
    Sleek and Collapsible.

    InputActionProperty has a lot of potential and I hope you will improve upon it! Having such an easy way for scaling your Input is a great thing (I mean there's the PlayerInput component but in my experience it kinda boxes you in).

    Code (CSharp):
    1. #nullable enable
    2. using System;
    3. using UnityEngine;
    4. using UnityEngine.InputSystem;
    5.  
    6. namespace UnityExtras.InputSystem
    7. {
    8.     [Serializable]
    9.     public struct Input : ISerializationCallbackReceiver
    10.     {
    11.         public bool enableOnStart;
    12.         public InputActionProperty inputActionProperty;
    13.         public InputAction? action => inputActionProperty.action;
    14.  
    15.         private bool _started;
    16.  
    17.         public void OnBeforeSerialize() { }
    18.  
    19.         public void OnAfterDeserialize() // Gets called when the struct first loads, even at runtime
    20.         {
    21.             if (enableOnStart && !_started)
    22.             {
    23.                 action?.Enable();
    24.             }
    25.             _started = true;
    26.         }
    27.     }
    28. }
    29.  
    Code (CSharp):
    1. #nullable enable
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. namespace UnityExtras.InputSystem.Editor
    6. {
    7.     [CustomPropertyDrawer(typeof(Input))]
    8.     public class InputDrawer : PropertyDrawer
    9.     {
    10.         public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    11.         {
    12.             EditorGUI.BeginProperty(position, label, property);
    13.  
    14.             position.y = position.yMin;
    15.             position.height = EditorGUIUtility.singleLineHeight;
    16.  
    17.             // Collect properties.
    18.             var enableOnStartProperty = property.FindPropertyRelative(nameof(Input.enableOnStart));
    19.  
    20.             var inputActionPropertyProperty = property.FindPropertyRelative(nameof(Input.inputActionProperty));
    21.             SerializedProperty m_UseReference = inputActionPropertyProperty.FindPropertyRelative(nameof(m_UseReference));
    22.             SerializedProperty m_Action = inputActionPropertyProperty.FindPropertyRelative(nameof(m_Action));
    23.             SerializedProperty m_Reference = inputActionPropertyProperty.FindPropertyRelative(nameof(m_Reference));
    24.  
    25.             // Draw the enable on construction toggle.
    26.             var enableOnStartPosition = new Rect(position);
    27.             enableOnStartPosition.x += EditorGUIUtility.labelWidth - EditorGUI.indentLevel * 18f;
    28.             enableOnStartPosition.width = 96f;
    29.             enableOnStartPosition.height = EditorGUIUtility.singleLineHeight;
    30.  
    31.             var defaultEnabledLabel = new GUIContent(enableOnStartProperty.displayName, "Should the action be enabled on start?");
    32.             EditorGUI.LabelField(enableOnStartPosition, defaultEnabledLabel);
    33.  
    34.             enableOnStartPosition.x += 96f;
    35.             enableOnStartPosition.width = position.width - EditorGUIUtility.labelWidth + EditorGUI.indentLevel * 18f - 96f;
    36.             EditorGUI.PropertyField(enableOnStartPosition, enableOnStartProperty, GUIContent.none);
    37.  
    38.             // Draw the use reference popup.
    39.             var useReferencePosition = new Rect(enableOnStartPosition);
    40.             useReferencePosition.x += 18f;
    41.             useReferencePosition.width -= 18f;
    42.             var selectedIndex = m_UseReference.boolValue ? 1 : 0;
    43.             EditorGUI.BeginChangeCheck();
    44.             selectedIndex = EditorGUI.Popup(useReferencePosition, selectedIndex, new[] { "Use Action", "Use Reference" });
    45.             if (EditorGUI.EndChangeCheck())
    46.             {
    47.                 m_UseReference.boolValue = selectedIndex == 1;
    48.             }
    49.  
    50.             // Draw the label.
    51.             var foldoutPosition = new Rect(position);
    52.             foldoutPosition.width = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * 18f;
    53.             property.isExpanded = EditorGUI.Foldout(foldoutPosition, property.isExpanded, label, true);
    54.  
    55.             if (property.isExpanded)
    56.             {
    57.                 position.y += EditorGUIUtility.singleLineHeight + 2f;
    58.                 EditorGUI.indentLevel++;
    59.  
    60.                 if (m_UseReference.boolValue)
    61.                 {
    62.                     position.height = EditorGUI.GetPropertyHeight(m_Reference, true);
    63.                     EditorGUI.PropertyField(position, m_Reference, true);
    64.                 }
    65.                 else
    66.                 {
    67.                     position.height = EditorGUI.GetPropertyHeight(m_Action, true);
    68.                     EditorGUI.PropertyField(position, m_Action, true);
    69.                 }
    70.  
    71.                 EditorGUI.indentLevel--;
    72.             }
    73.  
    74.             EditorGUI.EndProperty();
    75.         }
    76.  
    77.         public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    78.         {
    79.             var height = base.GetPropertyHeight(property, label);
    80.  
    81.             if (property.isExpanded)
    82.             {
    83.                 var inputActionPropertyProperty = property.FindPropertyRelative(nameof(Input.inputActionProperty));
    84.                 SerializedProperty m_UseReference = inputActionPropertyProperty.FindPropertyRelative(nameof(m_UseReference));
    85.                 SerializedProperty m_Action = inputActionPropertyProperty.FindPropertyRelative(nameof(m_Action));
    86.                 SerializedProperty m_Reference = inputActionPropertyProperty.FindPropertyRelative(nameof(m_Reference));
    87.  
    88.                 height += m_UseReference.boolValue ? EditorGUI.GetPropertyHeight(m_Reference, true) : EditorGUI.GetPropertyHeight(m_Action, true);
    89.                 height += 2f;
    90.             }
    91.  
    92.             return height;
    93.         }
    94.     }
    95. }
    96.