/// <summary>Adds functions to the `menu` relating to the thresholds.</summary> protected override void AddThresholdFunctionsToMenu(UnityEditor.GenericMenu menu) { AddPropertyModifierFunction(menu, "Evenly Spaced", (_) => { var count = CurrentThresholds.arraySize; if (count <= 1) { return; } var first = CurrentThresholds.GetArrayElementAtIndex(0).floatValue; var last = CurrentThresholds.GetArrayElementAtIndex(count - 1).floatValue; for (int i = 0; i < count; i++) { CurrentThresholds.GetArrayElementAtIndex(i).floatValue = Mathf.Lerp(first, last, i / (float)(count - 1)); } }); AddCalculateThresholdsFunction(menu, "From Speed", (clip, threshold) => clip.apparentSpeed); AddCalculateThresholdsFunction(menu, "From Velocity X", (clip, threshold) => clip.averageSpeed.x); AddCalculateThresholdsFunction(menu, "From Velocity Y", (clip, threshold) => clip.averageSpeed.z); AddCalculateThresholdsFunction(menu, "From Velocity Z", (clip, threshold) => clip.averageSpeed.z); AddCalculateThresholdsFunction(menu, "From Angular Speed (Rad)", (clip, threshold) => clip.averageAngularSpeed); AddCalculateThresholdsFunction(menu, "From Angular Speed (Deg)", (clip, threshold) => clip.averageAngularSpeed * Mathf.Rad2Deg); }
/************************************************************************************************************************/ /// <summary> /// Fills the `menu` with functions relevant to the `rootProperty`. /// </summary> public static void AddItemsToContextMenu(UnityEditor.GenericMenu menu, string prefix = "Calculate Thresholds/") { AddPropertyModifierFunction(menu, prefix + "Evenly Spaced", (_) => { var count = CurrentThresholds.arraySize; if (count <= 1) { return; } var first = CurrentThresholds.GetArrayElementAtIndex(0).floatValue; var last = CurrentThresholds.GetArrayElementAtIndex(count - 1).floatValue; for (int i = 0; i < count; i++) { CurrentThresholds.GetArrayElementAtIndex(i).floatValue = Mathf.Lerp(first, last, i / (float)(count - 1)); } }); AddCalculateThresholdsFunction(menu, prefix + "From Speed", (clip, threshold) => clip.apparentSpeed); AddCalculateThresholdsFunction(menu, prefix + "From Velocity X", (clip, threshold) => clip.averageSpeed.x); AddCalculateThresholdsFunction(menu, prefix + "From Velocity Y", (clip, threshold) => clip.averageSpeed.z); AddCalculateThresholdsFunction(menu, prefix + "From Velocity Z", (clip, threshold) => clip.averageSpeed.z); AddCalculateThresholdsFunction(menu, prefix + "From Angular Speed (Rad)", (clip, threshold) => clip.averageAngularSpeed * Mathf.Deg2Rad); AddCalculateThresholdsFunction(menu, prefix + "From Angular Speed (Deg)", (clip, threshold) => clip.averageAngularSpeed); }
private void AddCalculateThresholdsFunction(GenericMenu menu, string label, int axis, Func <AnimationClip, float, float> calculateThreshold) { AddPropertyModifierFunction(menu, label, (property) => { var count = CurrentClips.arraySize; for (int i = 0; i < count; i++) { var clip = CurrentClips.GetArrayElementAtIndex(i).objectReferenceValue as AnimationClip; if (clip == null) { continue; } var threshold = CurrentThresholds.GetArrayElementAtIndex(i); var value = threshold.vector2Value; var newValue = calculateThreshold(clip, value[axis]); if (!float.IsNaN(newValue)) { value[axis] = newValue; } threshold.vector2Value = value; } }); }
/************************************************************************************************************************/ private void InitialiseStandard4Directions(SerializedProperty property) { var oldSpeedCount = CurrentSpeeds.arraySize; CurrentClips.arraySize = CurrentThresholds.arraySize = CurrentSpeeds.arraySize = 5; CurrentThresholds.GetArrayElementAtIndex(0).vector2Value = Vector2.zero; CurrentThresholds.GetArrayElementAtIndex(1).vector2Value = Vector2.up; CurrentThresholds.GetArrayElementAtIndex(2).vector2Value = Vector2.right; CurrentThresholds.GetArrayElementAtIndex(3).vector2Value = Vector2.down; CurrentThresholds.GetArrayElementAtIndex(4).vector2Value = Vector2.left; InitialiseSpeeds(oldSpeedCount); var type = property.FindPropertyRelative("_Type"); type.enumValueIndex = (int)MixerType.Directional; }
/************************************************************************************************************************/ /// <inheritdoc/> protected override void AddThresholdFunctionsToMenu(UnityEditor.GenericMenu menu) { const string EvenlySpaced = "Evenly Spaced"; var count = CurrentThresholds.arraySize; if (count <= 1) { menu.AddDisabledItem(new GUIContent(EvenlySpaced)); } else { var first = CurrentThresholds.GetArrayElementAtIndex(0).floatValue; var last = CurrentThresholds.GetArrayElementAtIndex(count - 1).floatValue; if (last == first) { last++; } AddPropertyModifierFunction(menu, $"{EvenlySpaced} ({first} to {last})", (_) => { for (int i = 0; i < count; i++) { CurrentThresholds.GetArrayElementAtIndex(i).floatValue = Mathf.Lerp(first, last, i / (float)(count - 1)); } }); } AddCalculateThresholdsFunction(menu, "From Speed", (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.magnitude : float.NaN); AddCalculateThresholdsFunction(menu, "From Velocity X", (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.x : float.NaN); AddCalculateThresholdsFunction(menu, "From Velocity Y", (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.y : float.NaN); AddCalculateThresholdsFunction(menu, "From Velocity Z", (state, threshold) => AnimancerUtilities.TryGetAverageVelocity(state, out var velocity) ? velocity.z : float.NaN); AddCalculateThresholdsFunction(menu, "From Angular Speed (Rad)", (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed : float.NaN); AddCalculateThresholdsFunction(menu, "From Angular Speed (Deg)", (state, threshold) => AnimancerUtilities.TryGetAverageAngularSpeed(state, out var speed) ? speed * Mathf.Rad2Deg : float.NaN); }
/// <inheritdoc/> protected override void DoThresholdGUI(Rect area, int index) { var color = GUI.color; if (index > 0) { var previousThreshold = CurrentThresholds.GetArrayElementAtIndex(index - 1); var currentThreshold = CurrentThresholds.GetArrayElementAtIndex(index); if (previousThreshold.floatValue >= currentThreshold.floatValue) { if (_SortingErrorContent == null) { _SortingErrorContent = new GUIContent(Editor.AnimancerGUI.LoadIcon("console.erroricon.sml")) { tooltip = "Linear Mixer Thresholds must always be unique and sorted in ascending order (click to sort)" }; } if (_SortingErrorStyle == null) { _SortingErrorStyle = new GUIStyle(GUI.skin.label) { padding = new RectOffset(), } } ; var iconArea = Editor.AnimancerGUI.StealFromRight(ref area, area.height, Editor.AnimancerGUI.StandardSpacing); if (GUI.Button(iconArea, _SortingErrorContent, _SortingErrorStyle)) { Editor.Serialization.RecordUndo(Context.Property); ((LinearMixerTransition)Context.Transition).SortByThresholds(); } GUI.color = Editor.AnimancerGUI.ErrorFieldColor; } } base.DoThresholdGUI(area, index); GUI.color = color; }
/************************************************************************************************************************/ private static void AddCalculateThresholdsFunction(UnityEditor.GenericMenu menu, string label, Func <AnimationClip, float, float> calculateThreshold) { AddPropertyModifierFunction(menu, label, (property) => { var count = CurrentClips.arraySize; for (int i = 0; i < count; i++) { var clip = CurrentClips.GetArrayElementAtIndex(i).objectReferenceValue as AnimationClip; if (clip == null) { continue; } var threshold = CurrentThresholds.GetArrayElementAtIndex(i); threshold.floatValue = calculateThreshold(clip, threshold.floatValue); } }); }
/// <summary>Draws the GUI of the threshold at the specified `index`.</summary> protected override void DoThresholdGUI(Rect area, int index) { var color = GUI.color; if (index > 0) { var previousThreshold = CurrentThresholds.GetArrayElementAtIndex(index - 1); var currentThreshold = CurrentThresholds.GetArrayElementAtIndex(index); if (previousThreshold.floatValue >= currentThreshold.floatValue) { if (_SortingErrorContent == null) { _SortingErrorContent = UnityEditor.EditorGUIUtility.IconContent("console.erroricon.sml"); _SortingErrorContent.tooltip = "Linear Mixer Thresholds must always be sorted in ascending order (click to sort)"; _SortingErrorStyle = new GUIStyle(GUI.skin.label) { padding = new RectOffset(), }; } var iconArea = Editor.AnimancerGUI.StealFromRight(ref area, area.height, Editor.AnimancerGUI.StandardSpacing); if (GUI.Button(iconArea, _SortingErrorContent, _SortingErrorStyle)) { var transition = (Transition)Context.Transition; UnityEditor.Undo.RecordObjects(Context.Property.serializedObject.targetObjects, "Inspector"); transition.SortByThresholds(); } GUI.color = Editor.AnimancerGUI.ErrorFieldColor; } } base.DoThresholdGUI(area, index); GUI.color = color; }
/************************************************************************************************************************/ private void AddCalculateThresholdsFunction(UnityEditor.GenericMenu menu, string label, Func <Object, float, float> calculateThreshold) { AddPropertyModifierFunction(menu, label, (property) => { var count = CurrentAnimations.arraySize; for (int i = 0; i < count; i++) { var state = CurrentAnimations.GetArrayElementAtIndex(i).objectReferenceValue; if (state == null) { continue; } var threshold = CurrentThresholds.GetArrayElementAtIndex(i); var value = calculateThreshold(state, threshold.floatValue); if (!float.IsNaN(value)) { threshold.floatValue = value; } } }); }
/************************************************************************************************************************/ private void Initialize4Directions(SerializedProperty property) { var oldSpeedCount = CurrentSpeeds.arraySize; CurrentAnimations.arraySize = CurrentThresholds.arraySize = CurrentSpeeds.arraySize = 5; CurrentThresholds.GetArrayElementAtIndex(0).vector2Value = default;