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; } }); }
/************************************************************************************************************************/ /// <summary> /// Called when adding a new state to the list to ensure that any other relevant arrays have new /// elements added as well. /// </summary> protected virtual void OnAddElement(ReorderableList list) { var index = CurrentClips.arraySize; CurrentClips.InsertArrayElementAtIndex(index); if (CurrentSpeeds.arraySize > 0) { CurrentSpeeds.InsertArrayElementAtIndex(index); } }
/************************************************************************************************************************/ /// <summary> /// Recalculates the <see cref="CurrentSpeeds"/> depending on the <see cref="AnimationClip.length"/> of /// their animations so that they all take the same amount of time to play fully. /// </summary> private static void NormalizeDurations(SerializedProperty property) { var speedCount = CurrentSpeeds.arraySize; var lengths = new float[CurrentClips.arraySize]; if (lengths.Length <= 1) { return; } int nonZeroLengths = 0; float totalLength = 0; float totalSpeed = 0; for (int i = 0; i < lengths.Length; i++) { var clip = CurrentClips.GetArrayElementAtIndex(i).objectReferenceValue as AnimationClip; if (clip != null && clip.length > 0) { nonZeroLengths++; totalLength += clip.length; lengths[i] = clip.length; if (speedCount > 0) { totalSpeed += CurrentSpeeds.GetArrayElementAtIndex(i).floatValue; } } } if (nonZeroLengths == 0) { return; } var averageLength = totalLength / nonZeroLengths; var averageSpeed = speedCount > 0 ? totalSpeed / nonZeroLengths : 1; CurrentSpeeds.arraySize = lengths.Length; InitialiseSpeeds(speedCount); for (int i = 0; i < lengths.Length; i++) { if (lengths[i] == 0) { continue; } CurrentSpeeds.GetArrayElementAtIndex(i).floatValue = averageSpeed * lengths[i] / averageLength; } TryCollapseSpeeds(); }
/************************************************************************************************************************/ /// <summary>Draws the GUI of the state at the specified `index`.</summary> private void DoElementGUI(Rect area, int index, bool isActive, bool isFocused) { if (index < 0 || index > CurrentClips.arraySize) { return; } var clip = CurrentClips.GetArrayElementAtIndex(index); var speed = CurrentSpeeds.arraySize > 0 ? CurrentSpeeds.GetArrayElementAtIndex(index) : null; DoElementGUI(area, index, clip, speed); }
/************************************************************************************************************************/ 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); } }); }
/************************************************************************************************************************/ #endregion /************************************************************************************************************************/ #region Sync /************************************************************************************************************************/ /// <summary>Draws a "Sync" header.</summary> protected static void DoSyncHeaderGUI(Rect area) { var content = Editor.AnimancerGUI.TempContent("Sync", "Determines which child states have their normalized times constantly synchronised"); DoHeaderDropdownGUI(area, CurrentSpeeds, content, (menu) => { var syncCount = CurrentSynchroniseChildren.arraySize; var allState = syncCount == 0 ? Editor.MenuFunctionState.Selected : Editor.MenuFunctionState.Normal; AddPropertyModifierFunction(menu, "All", allState, (_) => CurrentSynchroniseChildren.arraySize = 0); var syncNone = syncCount == CurrentClips.arraySize; if (syncNone) { for (int i = 0; i < syncCount; i++) { if (CurrentSynchroniseChildren.GetArrayElementAtIndex(i).boolValue) { syncNone = false; break; } } } var noneState = syncNone ? Editor.MenuFunctionState.Selected : Editor.MenuFunctionState.Normal; AddPropertyModifierFunction(menu, "None", noneState, (_) => { var count = CurrentSynchroniseChildren.arraySize = CurrentClips.arraySize; for (int i = 0; i < count; i++) { CurrentSynchroniseChildren.GetArrayElementAtIndex(i).boolValue = false; } }); AddPropertyModifierFunction(menu, "Invert", Editor.MenuFunctionState.Normal, (_) => { var count = CurrentSynchroniseChildren.arraySize; for (int i = 0; i < count; i++) { var property = CurrentSynchroniseChildren.GetArrayElementAtIndex(i); property.boolValue = !property.boolValue; } var newCount = CurrentSynchroniseChildren.arraySize = CurrentClips.arraySize; for (int i = count; i < newCount; i++) { CurrentSynchroniseChildren.GetArrayElementAtIndex(i).boolValue = false; } }); AddPropertyModifierFunction(menu, "Non-Stationary", Editor.MenuFunctionState.Normal, (_) => { var count = CurrentClips.arraySize; for (int i = 0; i < count; i++) { var clip = CurrentClips.GetArrayElementAtIndex(i).objectReferenceValue as AnimationClip; if (clip == null) { continue; } if (i >= syncCount) { CurrentSynchroniseChildren.arraySize = i + 1; for (int j = syncCount; j < i; j++) { CurrentSynchroniseChildren.GetArrayElementAtIndex(j).boolValue = true; } syncCount = i + 1; } CurrentSynchroniseChildren.GetArrayElementAtIndex(i).boolValue = clip.averageSpeed != Vector3.zero; } TryCollapseSync(); }); }); }