Skip to content

Commit 76649d6

Browse files
committed
Refactoring of editor code, adding look sensitivity slider, added parameter override utility script.
1 parent c0720c1 commit 76649d6

13 files changed

+477
-481
lines changed

Assets/Samples/RebindingUI/ActionLabelEditor.cs

Lines changed: 4 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -15,38 +15,17 @@ public class ActionLabelEditor : UnityEditor.Editor
1515
{
1616
protected void OnEnable()
1717
{
18-
m_ActionProperty = serializedObject.FindProperty("m_Action");
19-
m_BindingIdProperty = serializedObject.FindProperty("m_BindingId");
2018
m_BindingTextProperty = serializedObject.FindProperty("m_BindingText");
21-
m_DisplayStringOptionsProperty = serializedObject.FindProperty("m_DisplayStringOptions");
2219
m_UpdateBindingUIEventProperty = serializedObject.FindProperty("m_UpdateBindingUIEvent");
23-
24-
RefreshBindingOptions();
20+
m_BindingUI = new BindingUI(serializedObject);
2521
}
2622

2723
public override void OnInspectorGUI()
2824
{
2925
EditorGUI.BeginChangeCheck();
3026

3127
// Binding section.
32-
EditorGUILayout.LabelField(m_BindingLabel, Styles.boldLabel);
33-
using (new EditorGUI.IndentLevelScope())
34-
{
35-
EditorGUILayout.PropertyField(m_ActionProperty);
36-
37-
var newSelectedBinding = EditorGUILayout.Popup(m_BindingLabel, m_SelectedBindingOption, m_BindingOptions);
38-
if (newSelectedBinding != m_SelectedBindingOption)
39-
{
40-
var bindingId = m_BindingOptionValues[newSelectedBinding];
41-
m_BindingIdProperty.stringValue = bindingId;
42-
m_SelectedBindingOption = newSelectedBinding;
43-
}
44-
45-
var optionsOld = (InputBinding.DisplayStringOptions)m_DisplayStringOptionsProperty.intValue;
46-
var optionsNew = (InputBinding.DisplayStringOptions)EditorGUILayout.EnumFlagsField(m_DisplayOptionsLabel, optionsOld);
47-
if (optionsOld != optionsNew)
48-
m_DisplayStringOptionsProperty.intValue = (int)optionsNew;
49-
}
28+
m_BindingUI.Draw();
5029

5130
// UI section.
5231
EditorGUILayout.Space();
@@ -67,91 +46,16 @@ public override void OnInspectorGUI()
6746
if (EditorGUI.EndChangeCheck())
6847
{
6948
serializedObject.ApplyModifiedProperties();
70-
RefreshBindingOptions();
71-
}
72-
}
73-
74-
protected void RefreshBindingOptions()
75-
{
76-
var actionReference = (InputActionReference)m_ActionProperty.objectReferenceValue;
77-
var action = actionReference?.action;
78-
79-
if (action == null)
80-
{
81-
m_BindingOptions = new GUIContent[0];
82-
m_BindingOptionValues = new string[0];
83-
m_SelectedBindingOption = -1;
84-
return;
85-
}
86-
87-
var bindings = action.bindings;
88-
var bindingCount = bindings.Count;
89-
90-
m_BindingOptions = new GUIContent[bindingCount];
91-
m_BindingOptionValues = new string[bindingCount];
92-
m_SelectedBindingOption = -1;
93-
94-
var currentBindingId = m_BindingIdProperty.stringValue;
95-
for (var i = 0; i < bindingCount; ++i)
96-
{
97-
var binding = bindings[i];
98-
var bindingId = binding.id.ToString();
99-
var haveBindingGroups = !string.IsNullOrEmpty(binding.groups);
100-
101-
// If we don't have a binding groups (control schemes), show the device that if there are, for example,
102-
// there are two bindings with the display string "A", the user can see that one is for the keyboard
103-
// and the other for the gamepad.
104-
var displayOptions =
105-
InputBinding.DisplayStringOptions.DontUseShortDisplayNames | InputBinding.DisplayStringOptions.IgnoreBindingOverrides;
106-
if (!haveBindingGroups)
107-
displayOptions |= InputBinding.DisplayStringOptions.DontOmitDevice;
108-
109-
// Create display string.
110-
var displayString = action.GetBindingDisplayString(i, displayOptions);
111-
112-
// If binding is part of a composite, include the part name.
113-
if (binding.isPartOfComposite)
114-
displayString = $"{ObjectNames.NicifyVariableName(binding.name)}: {displayString}";
115-
116-
// Some composites use '/' as a separator. When used in popup, this will lead to to submenus. Prevent
117-
// by instead using a backlash.
118-
displayString = displayString.Replace('/', '\\');
119-
120-
// If the binding is part of control schemes, mention them.
121-
if (haveBindingGroups)
122-
{
123-
var asset = action.actionMap?.asset;
124-
if (asset != null)
125-
{
126-
var controlSchemes = string.Join(", ",
127-
binding.groups.Split(InputBinding.Separator)
128-
.Select(x => asset.controlSchemes.FirstOrDefault(c => c.bindingGroup == x).name));
129-
130-
displayString = $"{displayString} ({controlSchemes})";
131-
}
132-
}
133-
134-
m_BindingOptions[i] = new GUIContent(displayString);
135-
m_BindingOptionValues[i] = bindingId;
136-
137-
if (currentBindingId == bindingId)
138-
m_SelectedBindingOption = i;
49+
m_BindingUI.Refresh();
13950
}
14051
}
14152

142-
private SerializedProperty m_ActionProperty;
143-
private SerializedProperty m_BindingIdProperty;
14453
private SerializedProperty m_BindingTextProperty;
14554
private SerializedProperty m_UpdateBindingUIEventProperty;
146-
private SerializedProperty m_DisplayStringOptionsProperty;
14755

148-
private GUIContent m_BindingLabel = new GUIContent("Binding");
149-
private GUIContent m_DisplayOptionsLabel = new GUIContent("Display Options");
15056
private GUIContent m_UILabel = new GUIContent("UI");
15157
private GUIContent m_EventsLabel = new GUIContent("Events");
152-
private GUIContent[] m_BindingOptions;
153-
private string[] m_BindingOptionValues;
154-
private int m_SelectedBindingOption;
58+
private BindingUI m_BindingUI;
15559

15660
private static class Styles
15761
{

Assets/Samples/RebindingUI/InputActionIndicator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class InputActionIndicator : MonoBehaviour
3434
private void OnEnable()
3535
{
3636
if (action != null && action.action != null)
37-
action.action.performed += OnPerformed;
37+
action.action.performed += OnPerformed; // TODO Problem here after domain reload, InputAction.addperformed(), CallbackArray.AddCallback,. InputArrayExtensions.Contains
3838
}
3939

4040
private void OnDisable()

Assets/Samples/RebindingUI/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ To demonstrate how to use images instead of textual display strings, take a look
44

55
To demonstrate how to show dynamic texts based on input action bindings, see [ActionLabel](./ActionLabel.cs).
66

7-
Finally, the [RebindSaveLoad](./RebindSaveLoad.cs) script demonstrates how to persist user rebinds in `PlayerPrefs` and how to restore them from there.
7+
Finally, the [RebindSaveLoad](./RebindSaveLoad.cs) script demonstrates how to persist user rebinds in `PlayerPrefs` and how to restore them from there.
88

9-
The icons used in the sample are taken from [Free Prompts Pack v4.0](https://opengameart.org/content/free-keyboard-and-controllers-prompts-pack) created by, and made available to public domain by Nicolae Berbece.
10-
Icons are licensed under [Creative Commons CC0](https://creativecommons.org/publicdomain/zero/1.0/).
9+
In this sample, keyboard bindings for "Move" (default WASD) is rebound as a single composite. This means that indivudual parts will get assigned one after
10+
the other. Another way of doing this is to set it up as four individual button bindings and assign them individually as four partial bindings.
11+
12+
In this sample it is possible to directly rebind gamepad sticks in the gamepad control scheme. In practice, you probably
13+
don't want to set up rebinding the sticks like this but rather have a "swap sticks" kind of toggle instead. In this
14+
sample we have both variants for demonstration purposes.
15+
16+
The icons used in the sample are taken from [Free Prompts Pack v4.0](https://opengameart.org/content/free-keyboard-and-controllers-prompts-pack) created by, and made available to public domain by Nicolae Berbece.
17+
Icons are licensed under [Creative Commons CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#if UNITY_EDITOR
2+
3+
using System;
4+
using System.Linq;
5+
using UnityEditor;
6+
7+
namespace UnityEngine.InputSystem.Samples.RebindUI
8+
{
9+
/// <summary>
10+
/// Common binding UI helper to allow editor composition.
11+
/// </summary>
12+
internal class BindingUI
13+
{
14+
private readonly SerializedProperty m_ActionProperty;
15+
private readonly SerializedProperty m_BindingIdProperty;
16+
private readonly SerializedProperty m_DisplayStringOptionsProperty;
17+
18+
public BindingUI(SerializedObject serializedObject)
19+
: this(serializedObject.FindProperty("m_Action"), serializedObject.FindProperty("m_BindingId"),
20+
serializedObject.FindProperty("m_DisplayStringOptions"))
21+
{}
22+
23+
public BindingUI(SerializedProperty actionProperty, SerializedProperty bindingIdProperty,
24+
SerializedProperty displayStringOptionsProperty = null)
25+
{
26+
m_ActionProperty = actionProperty;
27+
m_BindingIdProperty = bindingIdProperty;
28+
m_DisplayStringOptionsProperty = displayStringOptionsProperty;
29+
30+
Reset();
31+
Refresh();
32+
}
33+
34+
private void Reset()
35+
{
36+
bindingOptions = Array.Empty<GUIContent>();
37+
bindingOptionValues = Array.Empty<string>();
38+
selectedBindingIndex = -1;
39+
}
40+
41+
public void Draw()
42+
{
43+
// Binding section.
44+
EditorGUILayout.LabelField(m_BindingLabel);
45+
using (new EditorGUI.IndentLevelScope())
46+
{
47+
EditorGUILayout.PropertyField(m_ActionProperty);
48+
49+
var newSelectedBinding = EditorGUILayout.Popup(m_BindingLabel, selectedBindingIndex, bindingOptions);
50+
if (newSelectedBinding != selectedBindingIndex)
51+
{
52+
var bindingId = bindingOptionValues[newSelectedBinding];
53+
m_BindingIdProperty.stringValue = bindingId;
54+
selectedBindingIndex = newSelectedBinding;
55+
}
56+
57+
if (m_DisplayStringOptionsProperty != null)
58+
{
59+
var optionsOld = (InputBinding.DisplayStringOptions)m_DisplayStringOptionsProperty.intValue;
60+
var optionsNew = (InputBinding.DisplayStringOptions)EditorGUILayout.EnumFlagsField(m_DisplayOptionsLabel, optionsOld);
61+
if (optionsOld != optionsNew)
62+
m_DisplayStringOptionsProperty.intValue = (int)optionsNew;
63+
}
64+
}
65+
}
66+
67+
public bool Refresh()
68+
{
69+
if (action == null)
70+
{
71+
Reset();
72+
return false;
73+
}
74+
75+
var bindings = action.bindings;
76+
var bindingCount = bindings.Count;
77+
78+
bindingOptions = new GUIContent[bindingCount];
79+
bindingOptionValues = new string[bindingCount];
80+
selectedBindingIndex = -1;
81+
82+
var currentBindingId = m_BindingIdProperty.stringValue;
83+
for (var i = 0; i < bindingCount; ++i)
84+
{
85+
var binding = bindings[i];
86+
var bindingId = binding.id.ToString();
87+
var haveBindingGroups = !string.IsNullOrEmpty(binding.groups);
88+
89+
// If we don't have a binding groups (control schemes), show the device that if there are, for example,
90+
// there are two bindings with the display string "A", the user can see that one is for the keyboard
91+
// and the other for the gamepad.
92+
var displayOptions =
93+
InputBinding.DisplayStringOptions.DontUseShortDisplayNames | InputBinding.DisplayStringOptions.IgnoreBindingOverrides;
94+
if (!haveBindingGroups)
95+
displayOptions |= InputBinding.DisplayStringOptions.DontOmitDevice;
96+
97+
// Create display string.
98+
var displayString = action.GetBindingDisplayString(i, displayOptions);
99+
100+
// If binding is part of a composite, include the part name.
101+
if (binding.isPartOfComposite)
102+
displayString = $"{ObjectNames.NicifyVariableName(binding.name)}: {displayString}";
103+
104+
// Some composites use '/' as a separator. When used in popup, this will lead to to submenus. Prevent
105+
// by instead using a backlash.
106+
displayString = displayString.Replace('/', '\\');
107+
108+
// If the binding is part of control schemes, mention them.
109+
if (haveBindingGroups)
110+
{
111+
var asset = action.actionMap?.asset;
112+
if (asset != null)
113+
{
114+
var controlSchemes = string.Join(", ",
115+
binding.groups.Split(InputBinding.Separator)
116+
.Select(x => asset.controlSchemes.FirstOrDefault(c => c.bindingGroup == x).name));
117+
118+
displayString = $"{displayString} ({controlSchemes})";
119+
}
120+
}
121+
122+
bindingOptions[i] = new GUIContent(displayString);
123+
bindingOptionValues[i] = bindingId;
124+
125+
if (currentBindingId == bindingId)
126+
selectedBindingIndex = i;
127+
}
128+
129+
return true;
130+
}
131+
132+
public static int FindBindingById(InputAction action, string bindingId)
133+
{
134+
if (action == null || string.IsNullOrEmpty(bindingId)) return -1;
135+
var id = new Guid(bindingId);
136+
return action.bindings.IndexOf(x => x.id == id);
137+
}
138+
139+
public string bindingId => m_BindingIdProperty.stringValue;
140+
public int bindingIndex => FindBindingById(action, m_BindingIdProperty.stringValue);
141+
142+
public InputAction action => ((InputActionReference)m_ActionProperty.objectReferenceValue)?.action;
143+
144+
private GUIContent[] bindingOptions { get; set; }
145+
private string[] bindingOptionValues { get; set; }
146+
private int selectedBindingIndex { get; set; }
147+
148+
private readonly GUIContent m_BindingLabel = new GUIContent("Binding");
149+
private readonly GUIContent m_DisplayOptionsLabel = new GUIContent("Display Options");
150+
}
151+
}
152+
153+
#endif // UNITY_EDITOR

Assets/Samples/RebindingUI/RebindActionEditor.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)