A game about forced loneliness, made by TACStudios
at master 325 lines 12 kB view raw
1using System; 2using System.Collections.Generic; 3 4////TODO: support ProcessEventsManually 5////TODO: add way to pick by player index 6 7// Some fields assigned through only through serialization. 8#pragma warning disable CS0649 9 10namespace UnityEngine.InputSystem.Samples 11{ 12 /// <summary> 13 /// A component for debugging purposes that adds an on-screen display which shows 14 /// activity on an input action over time (<see cref="InputActionVisualizer.Visualization.Interaction"/>) 15 /// or an action's current value (<see cref="InputActionVisualizer.Visualization.Value"/>). 16 /// </summary> 17 /// <seealso cref="InputControlVisualizer"/> 18 [AddComponentMenu("Input/Debug/Input Action Visualizer")] 19 [ExecuteInEditMode] 20 public class InputActionVisualizer : InputVisualizer 21 { 22 /// <summary> 23 /// The action that is being visualized. May be null. 24 /// </summary> 25 public InputAction action => m_Action; 26 27 protected void FixedUpdate() 28 { 29 if (m_Visualization != Visualization.Value || m_Action == null || m_Visualizer == null) 30 return; 31 if (InputSystem.settings.updateMode != InputSettings.UpdateMode.ProcessEventsInFixedUpdate) 32 return; 33 RecordValue(Time.fixedTime); 34 } 35 36 protected void Update() 37 { 38 if (m_Visualization != Visualization.Value || m_Action == null || m_Visualizer == null) 39 return; 40 if (InputSystem.settings.updateMode != InputSettings.UpdateMode.ProcessEventsInDynamicUpdate) 41 return; 42 RecordValue(Time.time); 43 } 44 45 protected new void OnEnable() 46 { 47 if (m_Visualization == Visualization.None) 48 return; 49 50 base.OnEnable(); 51 52 ResolveAction(); 53 SetupVisualizer(); 54 55 if (s_EnabledInstances == null) 56 s_EnabledInstances = new List<InputActionVisualizer>(); 57 if (s_EnabledInstances.Count == 0) 58 InputSystem.onActionChange += OnActionChange; 59 s_EnabledInstances.Add(this); 60 } 61 62 protected new void OnDisable() 63 { 64 base.OnDisable(); 65 66 if (s_EnabledInstances != null) 67 { 68 s_EnabledInstances.Remove(this); 69 if (s_EnabledInstances.Count == 0) 70 InputSystem.onActionChange -= OnActionChange; 71 } 72 73 if (m_Visualization == Visualization.Interaction && m_Action != null) 74 { 75 m_Action.started -= OnActionTriggered; 76 m_Action.performed -= OnActionTriggered; 77 m_Action.canceled -= OnActionTriggered; 78 } 79 } 80 81 protected new void OnGUI() 82 { 83 if (m_Visualization == Visualization.None) 84 return; 85 86 if (Event.current.type != EventType.Repaint) 87 return; 88 89 base.OnGUI(); 90 91 if (m_ShowControlName && m_ActiveControlName != null) 92 VisualizationHelpers.DrawText(m_ActiveControlName, new Vector2(m_Rect.x, m_Rect.yMax), 93 VisualizationHelpers.ValueTextStyle); 94 } 95 96 private void RecordValue(double time) 97 { 98 Debug.Assert(m_Action != null); 99 Debug.Assert(m_Visualizer != null); 100 101 var value = m_Action.ReadValueAsObject(); 102 m_Visualizer.AddSample(value, time); 103 104 if (m_ShowControlName) 105 RecordControlName(); 106 } 107 108 private void RecordControlName() 109 { 110 var control = m_Action.activeControl; 111 if (control == m_ActiveControl) 112 return; 113 114 m_ActiveControl = control; 115 m_ActiveControlName = control != null ? new GUIContent(control.path) : null; 116 } 117 118 private void ResolveAction() 119 { 120 // If we have a reference to an action, try that first. 121 if (m_ActionReference != null) 122 m_Action = m_ActionReference.action; 123 124 // If we didn't get an action from that but we have an action name, 125 // just search through the currently enabled actions for one that 126 // matches by name. 127 if (m_Action == null && !string.IsNullOrEmpty(m_ActionName)) 128 { 129 var slashIndex = m_ActionName.IndexOf('/'); 130 var mapName = slashIndex != -1 ? m_ActionName.Substring(0, slashIndex) : null; 131 var actionName = slashIndex != -1 ? m_ActionName.Substring(slashIndex + 1) : m_ActionName; 132 133 var enabledActions = InputSystem.ListEnabledActions(); 134 foreach (var action in enabledActions) 135 { 136 if (string.Compare(actionName, action.name, StringComparison.InvariantCultureIgnoreCase) != 0) 137 continue; 138 139 if (mapName != null && action.actionMap != null && string.Compare(mapName, action.actionMap.name, 140 StringComparison.InvariantCultureIgnoreCase) != 0) 141 continue; 142 143 m_Action = action; 144 break; 145 } 146 } 147 148 // If we still don't have an action, there's nothing much for us to do. 149 // The action may show up at a later point. 150 if (m_Action == null) 151 return; 152 153 if (m_Visualization == Visualization.Interaction) 154 { 155 m_Action.performed += OnActionTriggered; 156 m_Action.started += OnActionTriggered; 157 m_Action.canceled += OnActionTriggered; 158 } 159 } 160 161 private void SetupVisualizer() 162 { 163 m_Visualizer = null; 164 if (m_Action == null) 165 return; 166 167 switch (m_Visualization) 168 { 169 case Visualization.Value: 170 switch (m_Action.type) 171 { 172 case InputActionType.Button: 173 m_Visualizer = new VisualizationHelpers.ScalarVisualizer<float> 174 { 175 limitMax = 1 176 }; 177 break; 178 179 case InputActionType.Value: 180 case InputActionType.PassThrough: 181 if (!string.IsNullOrEmpty(m_Action.expectedControlType)) 182 { 183 var layout = InputSystem.LoadLayout(m_Action.expectedControlType); 184 if (layout != null) 185 { 186 var valueType = layout.GetValueType(); 187 if (valueType == typeof(float)) 188 m_Visualizer = new VisualizationHelpers.ScalarVisualizer<float> 189 { 190 limitMax = 1 191 }; 192 else if (valueType == typeof(int)) 193 m_Visualizer = new VisualizationHelpers.ScalarVisualizer<int> 194 { 195 limitMax = 1 196 }; 197 else if (valueType == typeof(Vector2)) 198 m_Visualizer = new VisualizationHelpers.Vector2Visualizer(); 199 } 200 } 201 break; 202 } 203 break; 204 205 case Visualization.Interaction: 206 // We don't really know which interactions are sitting on the action and its bindings 207 // and while we could do and perform work to find out, it's simpler to just wait until 208 // we get input and then whatever interactions we encounter as we go along. Also keeps 209 // the visualization a little less cluttered. 210 m_Visualizer = new VisualizationHelpers.TimelineVisualizer(); 211 break; 212 } 213 } 214 215 private void OnActionDisabled() 216 { 217 } 218 219 private void OnActionTriggered(InputAction.CallbackContext context) 220 { 221 Debug.Assert(m_Visualization == Visualization.Interaction); 222 223 var timelineName = "Default"; 224 var interaction = context.interaction; 225 if (interaction != null) 226 { 227 timelineName = interaction.GetType().Name; 228 if (timelineName.EndsWith("Interaction")) 229 timelineName = timelineName.Substring(0, timelineName.Length - "Interaction".Length); 230 } 231 232 var visualizer = (VisualizationHelpers.TimelineVisualizer)m_Visualizer; 233 var timelineIndex = visualizer.GetTimeline(timelineName); 234 if (timelineIndex == -1) 235 { 236 Color color; 237 timelineIndex = visualizer.timelineCount; 238 if (timelineIndex < s_InteractionColors.Length) 239 color = s_InteractionColors[timelineIndex]; 240 else 241 color = new Color(Random.value, Random.value, Random.value, 1); 242 243 visualizer.AddTimeline(timelineName, color); 244 if (timelineIndex > 0) 245 visualizer.showLegend = true; 246 } 247 248 var time = (float)context.time; 249 switch (context.phase) 250 { 251 case InputActionPhase.Canceled: 252 visualizer.AddSample(timelineIndex, 0f, time); 253 break; 254 255 case InputActionPhase.Performed: 256 visualizer.AddSample(timelineIndex, 1f, time); 257 visualizer.AddSample(timelineIndex, 0f, time); 258 break; 259 260 case InputActionPhase.Started: 261 visualizer.AddSample(timelineIndex, 0.5f, time); 262 break; 263 } 264 265 if (m_ShowControlName) 266 RecordControlName(); 267 } 268 269 private static void OnActionChange(object actionOrMap, InputActionChange change) 270 { 271 switch (change) 272 { 273 case InputActionChange.ActionEnabled: 274 case InputActionChange.ActionMapEnabled: 275 for (var i = 0; i < s_EnabledInstances.Count; ++i) 276 if (s_EnabledInstances[i].m_Action == null) 277 { 278 s_EnabledInstances[i].ResolveAction(); 279 if (s_EnabledInstances[i].m_Action != null) 280 s_EnabledInstances[i].SetupVisualizer(); 281 } 282 break; 283 284 case InputActionChange.ActionDisabled: 285 for (var i = 0; i < s_EnabledInstances.Count; ++i) 286 if (actionOrMap == s_EnabledInstances[i].m_Action) 287 s_EnabledInstances[i].OnActionDisabled(); 288 break; 289 290 case InputActionChange.ActionMapDisabled: 291 for (var i = 0; i < s_EnabledInstances.Count; ++i) 292 if (s_EnabledInstances[i].m_Action?.actionMap == actionOrMap) 293 s_EnabledInstances[i].OnActionDisabled(); 294 break; 295 } 296 } 297 298 [SerializeField] private Visualization m_Visualization; 299 [SerializeField] private InputActionReference m_ActionReference; 300 [SerializeField] private string m_ActionName; 301 [SerializeField] private bool m_ShowControlName; 302 303 [NonSerialized] private InputAction m_Action; 304 [NonSerialized] private InputControl m_ActiveControl; 305 [NonSerialized] private GUIContent m_ActiveControlName; 306 307 private static List<InputActionVisualizer> s_EnabledInstances; 308 private static readonly Color[] s_InteractionColors = 309 { 310 new Color(1, 0, 0, 1), 311 new Color(0, 0, 1, 1), 312 new Color(1, 1, 0, 1), 313 new Color(1, 0, 1, 1), 314 new Color(0, 1, 1, 1), 315 new Color(0, 1, 0, 1), 316 }; 317 318 public enum Visualization 319 { 320 None, 321 Value, 322 Interaction, 323 } 324 } 325}