Unity實戰之制作動畫編輯器
為瞭更方便地為UI視圖添加動畫,將動畫的編輯功能封裝在瞭UI View類中,可以通過編輯器快速的為視圖編輯動畫。動畫分為兩種類型,一種是Unity中的Animator動畫,該類型直接通過一個字符串類型變量記錄動畫State狀態的名稱即可,播放時調用Animator類中的Play方法傳入該名稱。另一種是DoTween動畫,支持視圖的移動、旋轉、縮放、淡入淡出動畫的編輯:
首先看一下動畫相關的幾個類的數據結構:
using System; using UnityEngine; using DG.Tweening; namespace SK.Framework { /// <summary> /// UI移動動畫 /// </summary> [Serializable] public class UIMoveAnimation { public enum MoveMode { MoveIn, MoveOut } /// <summary> /// UI移動動畫方向 /// </summary> public enum UIMoveAnimationDirection { Left, Right, Top, Bottom, TopLeft, TopRight, MiddleCenter, BottomLeft, BottomRight, } public float duration = 1f; public float delay; public Ease ease = Ease.Linear; public UIMoveAnimationDirection direction = UIMoveAnimationDirection.Left; public bool isCustom; public Vector3 startValue; public Vector3 endValue; public MoveMode moveMode = MoveMode.MoveIn; public Tween Play(RectTransform target, bool instant = false) { Vector3 pos = Vector3.zero; float xOffset = target.rect.width / 2 + target.rect.width * target.pivot.x; float yOffset = target.rect.height / 2 + target.rect.height * target.pivot.y; switch (direction) { case UIMoveAnimationDirection.Left: pos = new Vector3(-xOffset, 0f, 0f); break; case UIMoveAnimationDirection.Right: pos = new Vector3(xOffset, 0f, 0f); break; case UIMoveAnimationDirection.Top: pos = new Vector3(0f, yOffset, 0f); break; case UIMoveAnimationDirection.Bottom: pos = new Vector3(0f, -yOffset, 0f); break; case UIMoveAnimationDirection.TopLeft: pos = new Vector3(-xOffset, yOffset, 0f); break; case UIMoveAnimationDirection.TopRight: pos = new Vector3(xOffset, yOffset, 0f); break; case UIMoveAnimationDirection.MiddleCenter: pos = Vector3.zero; break; case UIMoveAnimationDirection.BottomLeft: pos = new Vector3(-xOffset, -yOffset, 0f); break; case UIMoveAnimationDirection.BottomRight: pos = new Vector3(xOffset, -yOffset, 0f); break; } switch (moveMode) { case MoveMode.MoveIn: target.anchoredPosition3D = isCustom ? startValue : pos; return target.DOAnchorPos3D(endValue, instant ? 0f : duration).SetDelay(instant ? 0f : delay).SetEase(ease); case MoveMode.MoveOut: target.anchoredPosition3D = startValue; return target.DOAnchorPos3D(isCustom ? endValue : pos, instant ? 0f : duration).SetDelay(instant ? 0f : delay).SetEase(ease); default: return null; } } } }
using System; using UnityEngine; using DG.Tweening; namespace SK.Framework { /// <summary> /// UI旋轉動畫 /// </summary> [Serializable] public class UIRotateAnimation { public float duration = 1f; public float delay; public Ease ease = Ease.Linear; public Vector3 startValue; public Vector3 endValue; public RotateMode rotateMode = RotateMode.Fast; public bool isCustom; public Tween Play(RectTransform target, bool instant = false) { if (isCustom) { target.localRotation = Quaternion.Euler(startValue); } return target.DORotate(endValue, instant ? 0f : duration, rotateMode).SetDelay(instant ? 0f : delay).SetEase(ease); } } }
using System; using UnityEngine; using DG.Tweening; namespace SK.Framework { /// <summary> /// UI縮放動畫 /// </summary> [Serializable] public class UIScaleAnimation { public float duration = 1f; public float delay; public Ease ease = Ease.Linear; public Vector3 startValue = Vector3.zero; public Vector3 endValue = Vector3.one; public bool isCustom; public Tween Play(RectTransform target, bool instant = false) { if (isCustom) { target.localScale = startValue; } return target.DOScale(endValue, instant ? 0f : duration).SetDelay(instant ? 0f : delay).SetEase(ease); } } }
using System; using DG.Tweening; using UnityEngine; namespace SK.Framework { /// <summary> /// UI淡入淡出動畫 /// </summary> [Serializable] public class UIFadeAnimation { public float duration = 1f; public float delay; public Ease ease = Ease.Linear; public float startValue; public float endValue = 1f; public bool isCustom; public Tween Play(CanvasGroup target, bool instant = false) { if (isCustom) { target.alpha = startValue; } return target.DOFade(endValue, instant ? 0f : duration).SetDelay(instant ? 0f : delay).SetEase(ease); } } }
namespace SK.Framework { /// <summary> /// UI動畫類型 /// </summary> public enum UIAnimationType { /// <summary> /// DoTween動畫 /// </summary> Tween, /// <summary> /// Animator動畫 /// </summary> Animator, } }
using System; using UnityEngine; namespace SK.Framework { /// <summary> /// UI動畫 /// </summary> [Serializable] public class UIAnimation { public UIAnimationType animationType = UIAnimationType.Tween; public string stateName; public bool moveToggle; public UIMoveAnimation moveAnimation; public bool rotateToggle; public UIRotateAnimation rotateAnimation; public bool scaleToggle; public UIScaleAnimation scaleAnimation; public bool fadeToggle; public UIFadeAnimation fadeAnimation; public bool HasTweenAnimation { get { return moveToggle || rotateToggle || scaleToggle || fadeToggle; } } public IChain Play(UIView view, bool instant = false, Action callback = null) { switch (animationType) { case UIAnimationType.Tween: if (HasTweenAnimation) { var chain = view.Sequence(); var cc = new ConcurrentChain(); if (moveToggle) cc.Tween(() => moveAnimation.Play(view.RectTransform, instant)); if (rotateToggle) cc.Tween(() => rotateAnimation.Play(view.RectTransform, instant)); if (scaleToggle) cc.Tween(() => scaleAnimation.Play(view.RectTransform, instant)); if (fadeToggle) cc.Tween(() => fadeAnimation.Play(view.CanvasGroup, instant)); chain.Append(cc).Event(() => callback?.Invoke()).Begin(); return chain; } else { callback?.Invoke(); return null; } case UIAnimationType.Animator: return view.Sequence() .Animation(view.GetComponent<Animator>(), stateName) .Event(() => callback?.Invoke()) .Begin(); default: return null; } } } }
在UI View類中的相關變量如下:
using System; using UnityEngine.Events; namespace SK.Framework { [Serializable] public class ViewVisibilityChangedEvent { public UIAnimation animation = new UIAnimation(); public UnityEvent onBeginEvent; public UnityEvent onEndEvent; } }
為UI View創建Custom Editor:
using System; using UnityEngine; using UnityEditor; using DG.Tweening; using System.Reflection; using UnityEditor.Animations; using UnityEditor.AnimatedValues; namespace SK.Framework { [CustomEditor(typeof(UIView), true)] public class UIViewInspector : Editor { private enum Menu { Animation, UnityEvent, } private UIView Target; private SerializedProperty variables; private ViewVisibilityChangedEvent onShow; private ViewVisibilityChangedEvent onHide; private static string uiViewOnShowFoldout = "UIView OnShow Foldout"; private static string uiViewOnHideFoldout = "UIView OnHide Foldout"; private bool onShowFoldout; private bool onHideFoldout; private Menu onShowMenu = Menu.Animation; private Menu onHideMenu = Menu.Animation; private SerializedProperty onShowBeginEvent; private SerializedProperty onShowEndEvent; private SerializedProperty onHideBeginEvent; private SerializedProperty onHideEndEvent; private AnimBool onShowMoveAnimBool; private AnimBool onShowRotateAnimBool; private AnimBool onShowScaleAnimBool; private AnimBool onShowFadeAnimBool; private AnimBool onHideMoveAnimBool; private AnimBool onHideRotateAnimBool; private AnimBool onHideScaleAnimBool; private AnimBool onHideFadeAnimBool; private const float titleWidth = 80f; private const float labelWidth = 60f; public override void OnInspectorGUI() { if (Target == null) { Target = target as UIView; onShow = typeof(UIView).GetField("onVisible", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Target) as ViewVisibilityChangedEvent; onHide = typeof(UIView).GetField("onInvisible", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(Target) as ViewVisibilityChangedEvent; variables = serializedObject.FindProperty("variables"); onShowFoldout = EditorPrefs.GetBool(uiViewOnShowFoldout); onHideFoldout = EditorPrefs.GetBool(uiViewOnHideFoldout); onShowBeginEvent = serializedObject.FindProperty("onVisible").FindPropertyRelative("onBeginEvent"); onShowEndEvent = serializedObject.FindProperty("onVisible").FindPropertyRelative("onEndEvent"); onHideBeginEvent = serializedObject.FindProperty("onInvisible").FindPropertyRelative("onBeginEvent"); onHideEndEvent = serializedObject.FindProperty("onInvisible").FindPropertyRelative("onEndEvent"); onShowMoveAnimBool = new AnimBool(onShow.animation.moveToggle, Repaint); onShowRotateAnimBool = new AnimBool(onShow.animation.rotateToggle, Repaint); onShowScaleAnimBool = new AnimBool(onShow.animation.scaleToggle, Repaint); onShowFadeAnimBool = new AnimBool(onShow.animation.fadeToggle, Repaint); onHideMoveAnimBool = new AnimBool(onHide.animation.moveToggle, Repaint); onHideRotateAnimBool = new AnimBool(onHide.animation.rotateToggle, Repaint); onHideScaleAnimBool = new AnimBool(onHide.animation.scaleToggle, Repaint); onHideFadeAnimBool = new AnimBool(onHide.animation.fadeToggle, Repaint); } EditorGUILayout.PropertyField(variables); //On Show 折疊欄 var newOnShowFoldout = EditorGUILayout.Foldout(onShowFoldout, "On Visible", true); if (newOnShowFoldout != onShowFoldout) { onShowFoldout = newOnShowFoldout; EditorPrefs.SetBool(uiViewOnShowFoldout, onShowFoldout); } //Show if (onShowFoldout) { GUILayout.BeginHorizontal(); Color color = GUI.color; GUI.color = onShowMenu == Menu.Animation ? Color.cyan : color; if (GUILayout.Button("Animation", "ButtonLeft")) { onShowMenu = Menu.Animation; } GUI.color = onShowMenu == Menu.UnityEvent ? Color.cyan : color; if (GUILayout.Button("Event", "ButtonRight")) { onShowMenu = Menu.UnityEvent; } GUI.color = color; GUILayout.EndHorizontal(); switch (onShowMenu) { case Menu.Animation: //Animation Type GUILayout.BeginHorizontal(); GUILayout.Label("Mode", GUILayout.Width(titleWidth)); var newOnShowAnimationType = (UIAnimationType)EditorGUILayout.EnumPopup(onShow.animation.animationType); if (newOnShowAnimationType != onShow.animation.animationType) { Undo.RecordObject(Target, "On Show Animation Type"); onShow.animation.animationType = newOnShowAnimationType; EditorUtility.SetDirty(Target); } GUILayout.EndHorizontal(); UIAnimation animation = onShow.animation; switch (animation.animationType) { case UIAnimationType.Tween: //Move、Rotate、Scale、Fade GUILayout.BeginHorizontal(); { GUI.color = animation.moveToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("MoveTool"), "ButtonLeft", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Show Animation Move Toggle"); animation.moveToggle = !animation.moveToggle; onShowMoveAnimBool.target = animation.moveToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.rotateToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("RotateTool"), "ButtonMid", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Show Animation Rotate Toggle"); animation.rotateToggle = !animation.rotateToggle; onShowRotateAnimBool.target = animation.rotateToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.scaleToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("ScaleTool"), "ButtonMid", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Show Animation Scale Toggle"); animation.scaleToggle = !animation.scaleToggle; onShowScaleAnimBool.target = animation.scaleToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.fadeToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("ViewToolOrbit"), "ButtonRight", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Show Animation Fade Toggle"); animation.fadeToggle = !animation.fadeToggle; onShowFadeAnimBool.target = animation.fadeToggle; EditorUtility.SetDirty(Target); } GUI.color = color; } GUILayout.EndHorizontal(); //MoveAnimation var moveAnimation = animation.moveAnimation; if (EditorGUILayout.BeginFadeGroup(onShowMoveAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(40f); GUILayout.Label(EditorGUIUtility.IconContent("MoveTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(moveAnimation.duration); if (newDuration != moveAnimation.duration) { Undo.RecordObject(Target, "On Show Animation Move Duration"); moveAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(moveAnimation.delay); if (newDelay != moveAnimation.delay) { Undo.RecordObject(Target, "On Show Animation Move Delay"); moveAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(moveAnimation.isCustom ? "Custom Position" : "Direction", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Direction"), !moveAnimation.isCustom, () => { moveAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Custom Position"), moveAnimation.isCustom, () => { moveAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); if (moveAnimation.isCustom) { Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, moveAnimation.startValue); if (newStartValue != moveAnimation.startValue) { Undo.RecordObject(Target, "On Show Animation Move From"); moveAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } else { var newMoveDirection = (UIMoveAnimationDirection)EditorGUILayout.EnumPopup(moveAnimation.direction); if (newMoveDirection != moveAnimation.direction) { Undo.RecordObject(Target, "On Show Animation Move Direction"); moveAnimation.direction = newMoveDirection; EditorUtility.SetDirty(Target); } } } GUILayout.EndHorizontal(); //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, moveAnimation.endValue); if (newEndValue != moveAnimation.endValue) { Undo.RecordObject(Target, "On Show Animation Move To"); moveAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(moveAnimation.ease); if (newEase != moveAnimation.ease) { Undo.RecordObject(Target, "On Show Animation Move Ease"); moveAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //RotateAnimation var rotateAnimation = animation.rotateAnimation; if (EditorGUILayout.BeginFadeGroup(onShowRotateAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(rotateAnimation.isCustom ? 50f : 40f); GUILayout.Label(EditorGUIUtility.IconContent("RotateTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(rotateAnimation.duration); if (newDuration != rotateAnimation.duration) { Undo.RecordObject(Target, "On Show Animation Rotate Duration"); rotateAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(rotateAnimation.delay); if (newDelay != rotateAnimation.delay) { Undo.RecordObject(Target, "On Show Animation Rotate Delay"); rotateAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(rotateAnimation.isCustom ? "Fixed Rotation" : "Current Rotation", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Rotation"), !rotateAnimation.isCustom, () => { rotateAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Rotation"), rotateAnimation.isCustom, () => { rotateAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (rotateAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, rotateAnimation.startValue); if (newStartValue != rotateAnimation.startValue) { Undo.RecordObject(Target, "On Show Animation Rotate From"); rotateAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, rotateAnimation.endValue); if (newEndValue != rotateAnimation.endValue) { Undo.RecordObject(Target, "On Show Animation Rotate To"); rotateAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Rotate Mode GUILayout.BeginHorizontal(); { GUILayout.Label("Mode", GUILayout.Width(labelWidth)); var newRotateMode = (RotateMode)EditorGUILayout.EnumPopup(rotateAnimation.rotateMode); if (newRotateMode != rotateAnimation.rotateMode) { Undo.RecordObject(Target, "On Show Animation Rotate Mode"); rotateAnimation.rotateMode = newRotateMode; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(rotateAnimation.ease); if (newEase != rotateAnimation.ease) { Undo.RecordObject(Target, "On Show Animation Rotate Ease"); rotateAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //ScaleAnimation var scaleAnimation = animation.scaleAnimation; if (EditorGUILayout.BeginFadeGroup(onShowScaleAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(scaleAnimation.isCustom ? 40f : 30f); GUILayout.Label(EditorGUIUtility.IconContent("ScaleTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(scaleAnimation.duration); if (newDuration != scaleAnimation.duration) { Undo.RecordObject(Target, "On Show Animation Scale Duration"); scaleAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(scaleAnimation.delay); if (newDelay != scaleAnimation.delay) { Undo.RecordObject(Target, "On Show Animation Scale Delay"); scaleAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(scaleAnimation.isCustom ? "Fixed Scale" : "Current Scale", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Scale"), !scaleAnimation.isCustom, () => { scaleAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Scale"), scaleAnimation.isCustom, () => { scaleAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (scaleAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, scaleAnimation.startValue); if (newStartValue != scaleAnimation.startValue) { Undo.RecordObject(Target, "On Show Animation Scale From"); scaleAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, scaleAnimation.endValue); if (newEndValue != scaleAnimation.endValue) { Undo.RecordObject(Target, "On Show Animation Scale To"); scaleAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(scaleAnimation.ease); if (newEase != scaleAnimation.ease) { Undo.RecordObject(Target, "On Show Animation Scale Ease"); scaleAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //FadeAnimation var fadeAnimation = animation.fadeAnimation; if (EditorGUILayout.BeginFadeGroup(onShowFadeAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(fadeAnimation.isCustom ? 40f : 30f); GUILayout.Label(EditorGUIUtility.IconContent("ViewToolOrbit")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(fadeAnimation.duration); if (newDuration != fadeAnimation.duration) { Undo.RecordObject(Target, "On Show Animation Fade Duration"); fadeAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(fadeAnimation.delay); if (newDelay != fadeAnimation.delay) { Undo.RecordObject(Target, "On Show Animation Fade Delay"); fadeAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(fadeAnimation.isCustom ? "Fixed Alpha" : "Current Alpha", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Alpha"), !fadeAnimation.isCustom, () => { fadeAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Alpha"), fadeAnimation.isCustom, () => { fadeAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (fadeAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); float newStartValue = EditorGUILayout.FloatField(GUIContent.none, fadeAnimation.startValue); if (newStartValue != fadeAnimation.startValue) { Undo.RecordObject(Target, "On Show Animation Fade From"); fadeAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); float newEndValue = EditorGUILayout.FloatField(GUIContent.none, fadeAnimation.endValue); if (newEndValue != fadeAnimation.endValue) { Undo.RecordObject(Target, "On Show Animation Fade To"); fadeAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(fadeAnimation.ease); if (newEase != fadeAnimation.ease) { Undo.RecordObject(Target, "On Show Animation Fade Ease"); fadeAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); break; case UIAnimationType.Animator: var animator = Target.GetComponent<Animator>(); if (animator != null) { var animatorController = animator.runtimeAnimatorController as AnimatorController; var stateMachine = animatorController.layers[0].stateMachine; if (stateMachine.states.Length == 0) { EditorGUILayout.HelpBox("no animator state was found.", MessageType.Info); } else { string[] stateNames = new string[stateMachine.states.Length]; for (int i = 0; i < stateNames.Length; i++) { stateNames[i] = stateMachine.states[i].state.name; } var index = Array.FindIndex(stateNames, m => m == animation.stateName); GUILayout.BeginHorizontal(); GUILayout.Label("State Name", GUILayout.Width(titleWidth)); var newIndex = EditorGUILayout.Popup(index, stateNames); if (newIndex != index) { Undo.RecordObject(Target, "Show Animation State Name"); animation.stateName = stateNames[newIndex]; EditorUtility.SetDirty(Target); } GUILayout.EndHorizontal(); } } else { EditorGUILayout.HelpBox("no animator component on this view.", MessageType.Error); } break; default: break; } break; case Menu.UnityEvent: //OnBeginEvent、OnEndEvent EditorGUILayout.PropertyField(onShowBeginEvent); EditorGUILayout.PropertyField(onShowEndEvent); break; default: break; } } //On Hide 折疊欄 var newOnHideFoldout = EditorGUILayout.Foldout(onHideFoldout, "On Invisible", true); if (newOnHideFoldout != onHideFoldout) { onHideFoldout = newOnHideFoldout; EditorPrefs.SetBool(uiViewOnHideFoldout, onHideFoldout); } //Hide if (onHideFoldout) { GUILayout.BeginHorizontal(); Color color = GUI.color; GUI.color = onHideMenu == Menu.Animation ? Color.cyan : color; if (GUILayout.Button("Animation", "ButtonLeft")) { onHideMenu = Menu.Animation; } GUI.color = onHideMenu == Menu.UnityEvent ? Color.cyan : color; if (GUILayout.Button("Event", "ButtonRight")) { onHideMenu = Menu.UnityEvent; } GUI.color = color; GUILayout.EndHorizontal(); switch (onHideMenu) { case Menu.Animation: //Animation Type GUILayout.BeginHorizontal(); GUILayout.Label("Mode", GUILayout.Width(titleWidth)); var newOnHideAnimationType = (UIAnimationType)EditorGUILayout.EnumPopup(onHide.animation.animationType); if (newOnHideAnimationType != onHide.animation.animationType) { Undo.RecordObject(Target, "On Hide Animation Type"); onHide.animation.animationType = newOnHideAnimationType; } GUILayout.EndHorizontal(); UIAnimation animation = onHide.animation; switch (animation.animationType) { case UIAnimationType.Tween: //Move、Rotate、Scale、Fade GUILayout.BeginHorizontal(); { GUI.color = animation.moveToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("MoveTool"), "ButtonLeft", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Hide Animation Move Toggle"); animation.moveToggle = !animation.moveToggle; onHideMoveAnimBool.target = animation.moveToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.rotateToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("RotateTool"), "ButtonMid", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Hide Animation Rotate Toggle"); animation.rotateToggle = !animation.rotateToggle; onHideRotateAnimBool.target = animation.rotateToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.scaleToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("ScaleTool"), "ButtonMid", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Hide Animation Scale Toggle"); animation.scaleToggle = !animation.scaleToggle; onHideScaleAnimBool.target = animation.scaleToggle; EditorUtility.SetDirty(Target); } GUI.color = animation.fadeToggle ? color : Color.gray; if (GUILayout.Button(EditorGUIUtility.IconContent("ViewToolOrbit"), "ButtonRight", GUILayout.Width(25f))) { Undo.RecordObject(Target, "On Hide Animation Fade Toggle"); animation.fadeToggle = !animation.fadeToggle; onHideFadeAnimBool.target = animation.fadeToggle; EditorUtility.SetDirty(Target); } GUI.color = color; } GUILayout.EndHorizontal(); //MoveAnimation var moveAnimation = animation.moveAnimation; if (EditorGUILayout.BeginFadeGroup(onHideMoveAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(40f); GUILayout.Label(EditorGUIUtility.IconContent("MoveTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(moveAnimation.duration); if (newDuration != moveAnimation.duration) { Undo.RecordObject(Target, "On Hide Animation Move Duration"); moveAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(moveAnimation.delay); if (newDelay != moveAnimation.delay) { Undo.RecordObject(Target, "On Hide Animation Move Delay"); moveAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //From GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth)); Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, moveAnimation.startValue); if (newStartValue != moveAnimation.startValue) { Undo.RecordObject(Target, "On Hide Animation Move From"); moveAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(moveAnimation.isCustom ? "Custom Position" : "Direction", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Direction"), !moveAnimation.isCustom, () => { moveAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Custom Position"), moveAnimation.isCustom, () => { moveAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); //To GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); if (moveAnimation.isCustom) { Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, moveAnimation.endValue); if (newEndValue != moveAnimation.endValue) { Undo.RecordObject(Target, "On Hide Animation Move End"); moveAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } else { var newMoveDirection = (UIMoveAnimationDirection)EditorGUILayout.EnumPopup(moveAnimation.direction); if (newMoveDirection != moveAnimation.direction) { Undo.RecordObject(Target, "On Hide Animation Move Direction"); moveAnimation.direction = newMoveDirection; EditorUtility.SetDirty(Target); } } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(moveAnimation.ease); if (newEase != moveAnimation.ease) { Undo.RecordObject(Target, "On Hide Animation Move Ease"); moveAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //RotateAnimation var rotateAnimation = animation.rotateAnimation; if (EditorGUILayout.BeginFadeGroup(onHideRotateAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(rotateAnimation.isCustom ? 50f : 40f); GUILayout.Label(EditorGUIUtility.IconContent("RotateTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(rotateAnimation.duration); if (newDuration != rotateAnimation.duration) { Undo.RecordObject(Target, "On Hide Animation Rotate Duration"); rotateAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(rotateAnimation.delay); if (newDelay != rotateAnimation.delay) { Undo.RecordObject(Target, "On Hide Animation Rotate Delay"); rotateAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(rotateAnimation.isCustom ? "Fixed Rotation" : "Current Rotation", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Rotation"), !rotateAnimation.isCustom, () => { rotateAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Rotation"), rotateAnimation.isCustom, () => { rotateAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (rotateAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, rotateAnimation.startValue); if (newStartValue != rotateAnimation.startValue) { Undo.RecordObject(Target, "On Hide Animation Rotate From"); rotateAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, rotateAnimation.endValue); if (newEndValue != rotateAnimation.endValue) { Undo.RecordObject(Target, "On Hide Animation Rotate To"); rotateAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Rotate Mode GUILayout.BeginHorizontal(); { GUILayout.Label("Mode", GUILayout.Width(labelWidth)); var newRotateMode = (RotateMode)EditorGUILayout.EnumPopup(rotateAnimation.rotateMode); if (newRotateMode != rotateAnimation.rotateMode) { Undo.RecordObject(Target, "On Hide Animation Rotate Mode"); rotateAnimation.rotateMode = newRotateMode; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(rotateAnimation.ease); if (newEase != rotateAnimation.ease) { Undo.RecordObject(Target, "On Hide Animation Rotate Ease"); rotateAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //ScaleAnimation var scaleAnimation = animation.scaleAnimation; if (EditorGUILayout.BeginFadeGroup(onHideScaleAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(scaleAnimation.isCustom ? 40f : 30f); GUILayout.Label(EditorGUIUtility.IconContent("ScaleTool")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(scaleAnimation.duration); if (newDuration != scaleAnimation.duration) { Undo.RecordObject(Target, "On Hide Animation Scale Duration"); scaleAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(scaleAnimation.delay); if (newDelay != scaleAnimation.delay) { Undo.RecordObject(Target, "On Hide Animation Scale Delay"); scaleAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(scaleAnimation.isCustom ? "Fixed Scale" : "Current Scale", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Scale"), !scaleAnimation.isCustom, () => { scaleAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Scale"), scaleAnimation.isCustom, () => { scaleAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (scaleAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); Vector3 newStartValue = EditorGUILayout.Vector3Field(GUIContent.none, scaleAnimation.startValue); if (newStartValue != scaleAnimation.startValue) { Undo.RecordObject(Target, "On Hide Animation Scale From"); scaleAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); Vector3 newEndValue = EditorGUILayout.Vector3Field(GUIContent.none, scaleAnimation.endValue); if (newEndValue != scaleAnimation.endValue) { Undo.RecordObject(Target, "On Hide Animation Scale To"); scaleAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(scaleAnimation.ease); if (newEase != scaleAnimation.ease) { Undo.RecordObject(Target, "On Hide Animation Scale Ease"); scaleAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); //FadeAnimation var fadeAnimation = animation.fadeAnimation; if (EditorGUILayout.BeginFadeGroup(onHideFadeAnimBool.faded)) { GUILayout.BeginHorizontal("Badge"); { GUILayout.BeginVertical(); { GUILayout.Space(fadeAnimation.isCustom ? 40f : 30f); GUILayout.Label(EditorGUIUtility.IconContent("ViewToolOrbit")); } GUILayout.EndVertical(); GUILayout.BeginVertical(); { //Duration、Delay GUILayout.BeginHorizontal(); { GUILayout.Label("Duration", GUILayout.Width(labelWidth)); var newDuration = EditorGUILayout.FloatField(fadeAnimation.duration); if (newDuration != fadeAnimation.duration) { Undo.RecordObject(Target, "On Hide Animation Fade Duration"); fadeAnimation.duration = newDuration; EditorUtility.SetDirty(Target); } GUILayout.Label("Delay", GUILayout.Width(labelWidth - 20f)); var newDelay = EditorGUILayout.FloatField(fadeAnimation.delay); if (newDelay != fadeAnimation.delay) { Undo.RecordObject(Target, "On Hide Animation Fade Delay"); fadeAnimation.delay = newDelay; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Is Custom GUILayout.BeginHorizontal(); { GUILayout.Label("From", GUILayout.Width(labelWidth - 2f)); if (GUILayout.Button(fadeAnimation.isCustom ? "Fixed Alpha" : "Current Alpha", "DropDownButton")) { GenericMenu gm = new GenericMenu(); gm.AddItem(new GUIContent("Current Alpha"), !fadeAnimation.isCustom, () => { fadeAnimation.isCustom = false; EditorUtility.SetDirty(Target); }); gm.AddItem(new GUIContent("Fixed Alpha"), fadeAnimation.isCustom, () => { fadeAnimation.isCustom = true; EditorUtility.SetDirty(Target); }); gm.ShowAsContext(); } } GUILayout.EndHorizontal(); if (fadeAnimation.isCustom) { //From GUILayout.BeginHorizontal(); { GUILayout.Label(GUIContent.none, GUILayout.Width(labelWidth)); float newStartValue = EditorGUILayout.FloatField(GUIContent.none, fadeAnimation.startValue); if (newStartValue != fadeAnimation.startValue) { Undo.RecordObject(Target, "On Hide Animation Fade From"); fadeAnimation.startValue = newStartValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } //To GUILayout.BeginHorizontal(); { GUILayout.Label("To", GUILayout.Width(labelWidth)); float newEndValue = EditorGUILayout.FloatField(GUIContent.none, fadeAnimation.endValue); if (newEndValue != fadeAnimation.endValue) { Undo.RecordObject(Target, "On Hide Animation Fade To"); fadeAnimation.endValue = newEndValue; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); //Ease GUILayout.BeginHorizontal(); { GUILayout.Label("Ease", GUILayout.Width(labelWidth)); var newEase = (Ease)EditorGUILayout.EnumPopup(fadeAnimation.ease); if (newEase != fadeAnimation.ease) { Undo.RecordObject(Target, "On Hide Animation Fade Ease"); fadeAnimation.ease = newEase; EditorUtility.SetDirty(Target); } } GUILayout.EndHorizontal(); } GUILayout.EndVertical(); } GUILayout.EndHorizontal(); } EditorGUILayout.EndFadeGroup(); break; case UIAnimationType.Animator: var animator = Target.GetComponent<Animator>(); if (animator != null) { var animatorController = animator.runtimeAnimatorController as AnimatorController; var stateMachine = animatorController.layers[0].stateMachine; if (stateMachine.states.Length == 0) { EditorGUILayout.HelpBox("no animator state was found.", MessageType.Info); } else { string[] stateNames = new string[stateMachine.states.Length]; for (int i = 0; i < stateNames.Length; i++) { stateNames[i] = stateMachine.states[i].state.name; } var index = Array.FindIndex(stateNames, m => m == animation.stateName); GUILayout.BeginHorizontal(); GUILayout.Label("State Name", GUILayout.Width(titleWidth)); var newIndex = EditorGUILayout.Popup(index, stateNames); if (newIndex != index) { Undo.RecordObject(Target, "Show Animation State Name"); animation.stateName = stateNames[newIndex]; EditorUtility.SetDirty(Target); } GUILayout.EndHorizontal(); } } else { EditorGUILayout.HelpBox("no animator component on this view.", MessageType.Error); } break; default: break; } break; case Menu.UnityEvent: //OnBeginEvent、OnEndEvent EditorGUILayout.PropertyField(onHideBeginEvent); EditorGUILayout.PropertyField(onHideEndEvent); break; default: break; } } serializedObject.ApplyModifiedProperties(); } } }
以上就是Unity實戰之制作動畫編輯器的詳細內容,更多關於Unity動畫編輯器的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Unity實現批量Build打包詳解
- Unity 制作一個分數統計系統
- 前端html+css實現動態生日快樂代碼
- Thinkphp自定義美化success和error提示跳轉頁面代碼實例
- Android實現旋轉動畫