/************************************************************************************************************************/ /// <summary> /// Draws the <see cref="Animator.cullingMode"/> field. /// </summary> private void DoCullingModeGUI() { if (_CullingMode == null) { return; } var label = AnimancerEditorUtilities.TempContent("Culling Mode", "Controls what is updated when the object has been culled (when it is not being rendered by a Camera)"); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_CullingMode, label); if (EditorGUI.EndChangeCheck()) { _OnEndGUI += () => { for (int i = 0; i < Targets.Length; i++) { var animator = _Animators[i]; if (animator != null) { AnimancerEditorUtilities.Invoke(animator, "OnCullingModeChanged"); } } }; } }
private void DoRootMotionGUI() { if (_RootMotion == null) { return; } var animator = _Animators[0]; if (_Animators.Length == 1 && (bool)AnimancerEditorUtilities.Invoke(animator, "get_supportsOnAnimatorMove")) { EditorGUILayout.LabelField("Apply Root Motion", "Handled by Script"); } else { EditorGUILayout.PropertyField(_RootMotion, AnimancerEditorUtilities.TempContent("Apply Root Motion", "If enabled, the Animator will automatically move the object using the root motion from the animations")); if (Event.current.type == EventType.Layout) { _IsRootPositionOrRotationControlledByCurves = (bool)AnimancerEditorUtilities.Invoke(animator, "get_isRootPositionOrRotationControlledByCurves"); } if (_IsRootPositionOrRotationControlledByCurves && !_RootMotion.boolValue) { EditorGUILayout.HelpBox("Root position or rotation are controlled by curves", MessageType.Info, true); } } }
private void DrawAnimationsHeader(Rect area) { var labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth -= 6; area.width += 5; var property = _Animations.serializedProperty; var label = AnimancerEditorUtilities.TempContent(property.displayName, property.tooltip); EditorGUI.BeginProperty(area, label, property); if (_AnimationsArraySize == null) { _AnimationsArraySize = property.Copy(); _AnimationsArraySize.Next(true); _AnimationsArraySize.Next(true); } EditorGUI.PropertyField(area, _AnimationsArraySize, label); EditorGUI.EndProperty(); EditorGUIUtility.labelWidth = labelWidth; }
/************************************************************************************************************************/ private void DoDefaultAnimationField(SerializedProperty property) { var area = AnimancerEditorUtilities.GetRect(); var label = AnimancerEditorUtilities.TempContent("Default Animation", "If 'Play Automatically' is enabled, this animation will be played by OnEnable"); SerializedProperty firstElement; AnimationClip clip; if (property.arraySize > 0) { firstElement = property.GetArrayElementAtIndex(0); clip = (AnimationClip)firstElement.objectReferenceValue; label = EditorGUI.BeginProperty(area, label, firstElement); } else { firstElement = null; clip = null; label = EditorGUI.BeginProperty(area, label, property); } EditorGUI.BeginChangeCheck(); clip = (AnimationClip)EditorGUI.ObjectField(area, label, clip, typeof(AnimationClip), true); if (EditorGUI.EndChangeCheck()) { if (clip != null) { if (firstElement == null) { property.arraySize = 1; firstElement = property.GetArrayElementAtIndex(0); } firstElement.objectReferenceValue = clip; } else { if (firstElement == null || property.arraySize == 1) { property.arraySize = 0; } else { firstElement.objectReferenceValue = clip; } } } EditorGUI.EndProperty(); }
private bool DoNormalizedTimeToggle(ref Rect area) { var content = AnimancerEditorUtilities.TempContent("N"); var style = AnimancerEditorUtilities.Styles.MiniButton; if (_UseNormalizedTimeSlidersWidth == 0) { _UseNormalizedTimeSlidersWidth = style.CalculateWidth(content); } var toggleArea = AnimancerEditorUtilities.StealWidth(ref area, _UseNormalizedTimeSlidersWidth); UseNormalizedTimeSliders.Value = GUI.Toggle(toggleArea, UseNormalizedTimeSliders, content, style); return(UseNormalizedTimeSliders); }
/// <summary> /// Draws the animator reference field followed by its fields that are relevant to Animancer. /// </summary> public void DoInspectorGUI() { _OnEndGUI = null; DoAnimatorGUI(); GatherAnimatorProperties(); if (_SerializedAnimator == null) { return; } _SerializedAnimator.Update(); AnimancerEditorUtilities.BeginVerticalBox(EditorStyles.helpBox); { if (!_IsAnimatorOnSameObject) { EditorGUILayout.HelpBox("It is recommended that you keep this component on the same GameObject" + " as its target Animator so that they get enabled and disabled at the same time.", MessageType.Info); } DoControllerGUI(); EditorGUILayout.PropertyField(_Avatar, AnimancerEditorUtilities.TempContent("Avatar", "The Avatar used by the Animator")); DoRootMotionGUI(); DoUpdateModeGUI(true); DoCullingModeGUI(); DoStopOnDisableGUI(_KeepStateOnDisable, false); } AnimancerEditorUtilities.EndVerticalBox(EditorStyles.helpBox); _SerializedAnimator.ApplyModifiedProperties(); if (_OnEndGUI != null) { _OnEndGUI(); _OnEndGUI = null; } }
/************************************************************************************************************************/ /// <summary> /// Draws the <see cref="Animator.keepAnimatorControllerStateOnDisable"/> field. /// </summary> public static void DoStopOnDisableGUI(SerializedProperty keepStateOnDisable, bool updateAndApply) { #if UNITY_2018_1_OR_NEWER var area = AnimancerEditorUtilities.GetRect(); var label = AnimancerEditorUtilities.TempContent("Stop On Disable", "If true, disabling this object will stop and rewind all animations." + " Otherwise they will simply be paused and will resume from their current states when it is re-enabled."); if (keepStateOnDisable != null) { if (updateAndApply) { keepStateOnDisable.serializedObject.Update(); } label = EditorGUI.BeginProperty(area, label, keepStateOnDisable); keepStateOnDisable.boolValue = !EditorGUI.Toggle(area, label, !keepStateOnDisable.boolValue); EditorGUI.EndProperty(); if (updateAndApply) { keepStateOnDisable.serializedObject.ApplyModifiedProperties(); } } else { var enabled = GUI.enabled; GUI.enabled = false; EditorGUI.Toggle(area, label, false); GUI.enabled = enabled; } #endif }
/************************************************************************************************************************/ /// <summary> /// Draws the <see cref="Animator.updateMode"/> field with any appropriate warnings. /// </summary> private void DoUpdateModeGUI(bool showWithoutWarning) { if (_UpdateMode == null) { return; } var label = AnimancerEditorUtilities.TempContent("Update Mode", "Controls when and how often the animations are updated"); var initialUpdateMode = Targets[0].InitialUpdateMode; var updateMode = (AnimatorUpdateMode)_UpdateMode.intValue; EditorGUI.BeginChangeCheck(); if (!EditorApplication.isPlaying || !AnimancerPlayable.HasChangedToOrFromAnimatePhysics(initialUpdateMode, updateMode)) { if (showWithoutWarning) { EditorGUILayout.PropertyField(_UpdateMode, label); } } else { GUILayout.BeginHorizontal(); var color = GUI.color; GUI.color = AnimancerEditorUtilities.WarningFieldColor; EditorGUILayout.PropertyField(_UpdateMode, label); GUI.color = color; label = AnimancerEditorUtilities.TempContent("Revert", "Revert to initial mode"); if (GUILayout.Button(label, EditorStyles.miniButton, AnimancerEditorUtilities.DontExpandWidth)) { _UpdateMode.intValue = (int)initialUpdateMode.Value; } GUILayout.EndHorizontal(); EditorGUILayout.HelpBox( "Changing to or from AnimatePhysics mode at runtime has no effect when using the" + " Playables API. It will continue using the original mode it had on startup.", MessageType.Warning); if (AnimancerEditorUtilities.TryUseClickInLastRect()) { EditorUtility.OpenWithDefaultApp(AnimancerPlayable.APIDocumentationURL + "/docs/unity-bugs/update-modes"); } } if (EditorGUI.EndChangeCheck()) { _OnEndGUI += () => { for (int i = 0; i < _Animators.Length; i++) { var animator = _Animators[i]; if (animator != null) { AnimancerEditorUtilities.Invoke(animator, "OnUpdateModeChanged"); } } }; } }
/************************************************************************************************************************/ /// <summary> /// Draws the <see cref="Animator.runtimeAnimatorController"/> field with a warning if a controller is /// assigned. /// </summary> private void DoControllerGUI() { if (_Controller == null) { return; } var controller = _Animators[0].runtimeAnimatorController; var showMixedValue = EditorGUI.showMixedValue; for (int i = 1; i < _Animators.Length; i++) { if (_Animators[i].runtimeAnimatorController != controller) { EditorGUI.showMixedValue = true; break; } } if (controller == null && !EditorGUI.showMixedValue) { return; } var label = AnimancerEditorUtilities.TempContent("Controller"); EditorGUI.BeginChangeCheck(); var area = EditorGUILayout.BeginHorizontal(); label = EditorGUI.BeginProperty(area, label, _Controller); var color = GUI.color; GUI.color = AnimancerEditorUtilities.WarningFieldColor; controller = (RuntimeAnimatorController)EditorGUILayout.ObjectField(label, controller, typeof(RuntimeAnimatorController), false); GUI.color = color; if (GUILayout.Button("Remove", EditorStyles.miniButton, AnimancerEditorUtilities.DontExpandWidth)) { controller = null; } GUILayout.EndHorizontal(); if (EditorGUI.EndChangeCheck()) { Undo.RecordObjects(_Animators, "Changed AnimatorController"); for (int i = 0; i < _Animators.Length; i++) { _Animators[i].runtimeAnimatorController = controller; } OnControllerChanged(); } EditorGUI.showMixedValue = showMixedValue; EditorGUILayout.HelpBox( "The AnimatorController will not affect the model while Animancer is active," + " however Unity will still execute it's state machine in the background," + " which may be a waste of processing time if you aren't using it intentionally." + " Click here for more information.", MessageType.Warning); if (AnimancerEditorUtilities.TryUseClickInLastRect()) { EditorUtility.OpenWithDefaultApp(AnimancerPlayable.APIDocumentationURL + "/docs/manual/animator-controller-states"); } }