美术同学在做某些场景的效果的时候可能需要多个动画来实现一些效果,组合调试的时候每次都要运行,比较麻烦,所以希望有一个Editor模式下的动画预览工具,方便美术同学开发。
界面如下:
使用也很方便,选择场景中的一个或多个gameObject,点击重新载入动画,就会生成动画控制器列表,支持Animation和Animator,自动生成动画列表,可以选择播放动画器下的动画,拖动进度或者点击播放按钮即可。
支持以下功能:
1.多动画控制器,同时支持Animation和Animator;
2.支持选择动画,并显示当前播放长度和总动画长度;
3.显示动画播放进度百分比,支持拖动百分比播放动画;
4.支持倍速;
5.支持循环播放。
将以下代码放到一个Editor目录即可
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
namespace Common.Tools.Editor
{
public class AnimationClipViewer : EditorWindow
{
[UnityEditor.MenuItem("Tools/动画预览工具", false)]
public static void ShowWindow()
{
AnimationClipViewer animationClipViewer = EditorWindow.GetWindow(true, "动画预览工具");
animationClipViewer.position = new Rect(300, 200, 800, 600);
}
private static Dictionary clipsDic = new Dictionary();
private static Dictionary clipIndexDic = new Dictionary();
private static float m_SliderValue = 0f, m_SliderValue1 = 0;
private static bool loop = false;
private static bool isPlaying = false;
private static bool autoPlay = false;
private static float startTime = 0;
private static float speed = 1f;
private static float length = 0f;
void OnInspectorUpdate() { }
void OnGUI()
{
EditorGUILayout.LabelField("选择预制体", new[] { GUILayout.Height(20), GUILayout.Width(500) });
if (GUILayout.Button("重新载入动画", new[] { GUILayout.Height(20), GUILayout.Width(80) }))
{
clipsDic.Clear();
clipIndexDic.Clear();
if (Selection.gameObjects != null && Selection.gameObjects.Length > 0)
{
GameObject[] gos = Selection.gameObjects;
foreach (var go in gos)
{
Animation[] animations = go.GetComponentsInChildren(true);
if (animations != null && animations.Length > 0)
{
foreach (var animation in animations)
{
List clips = new List();
foreach (AnimationState _state in animation)
{
clips.Add(animation.GetClip(_state.name));
Debug.Log(_state.name);
}
clipsDic.Add(animation.gameObject, clips.ToArray());
clipIndexDic.Add(animation.gameObject, 0);
}
}
Animator[] animators = go.GetComponentsInChildren(true);
if (animators != null && animators.Length > 0)
{
foreach (var animator in animators)
{
AnimatorController controller = (AnimatorController)animator.runtimeAnimatorController;
clipsDic.Add(animator.gameObject, controller.animationClips);
clipIndexDic.Add(animator.gameObject, 0);
}
}
}
}
}
if (clipsDic.Count == 0) return;
EditorGUI.BeginChangeCheck();
foreach (var kvp in clipsDic)
{
int selectIndex = clipIndexDic[kvp.Key];
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField(kvp.Key.name, new[] { GUILayout.Height(20), GUILayout.Width(100) });
selectIndex = EditorGUILayout.Popup("选择动画:", selectIndex, kvp.Value.Select(pkg => pkg.name).ToArray(), new[] { GUILayout.Height(20), GUILayout.Width(400) });
AnimationClip clip = kvp.Value[selectIndex];
float time = clip.length * m_SliderValue;
if (clip.length > length)//取最长的
length = clip.length;
EditorGUILayout.LabelField($"长度:{time}/{clip.length}s", new[] { GUILayout.Height(20), GUILayout.Width(100) });
clipIndexDic[kvp.Key] = selectIndex;
EditorGUILayout.EndHorizontal();
}
m_SliderValue = EditorGUILayout.Slider("播放进度", m_SliderValue, 0f, 1f);
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
speed = EditorGUILayout.Slider("倍速", speed, 0f, 10f, new[] { GUILayout.Height(20), GUILayout.Width(400) });
if (GUILayout.Button("正常", new[] { GUILayout.Height(20), GUILayout.Width(80) }))
{
speed = 1f;
}
EditorGUILayout.EndHorizontal();
if (EditorGUI.EndChangeCheck())
{
autoPlay = false;
foreach (var kvp in clipsDic)
{
int selectIndex = clipIndexDic[kvp.Key];
AnimationClip clip = kvp.Value[selectIndex];
float time = clip.length * m_SliderValue;
clip.SampleAnimation(kvp.Key, time);
}
}
EditorGUILayout.Space();
EditorGUILayout.BeginHorizontal();
loop = GUILayout.Toggle(loop, "循环", new[] { GUILayout.Height(20), GUILayout.Width(200) });
if (isPlaying)
{
if (GUILayout.Button("停止", new[] { GUILayout.Height(20), GUILayout.Width(100) }))
{
autoPlay = false;
isPlaying = false;
}
}
else
{
if (GUILayout.Button("播放", new[] { GUILayout.Height(20), GUILayout.Width(100) }))
{
m_SliderValue = 0f;
isPlaying = true;
autoPlay = true;
startTime = Time.realtimeSinceStartup;
Debug.Log(startTime);
}
}
EditorGUILayout.EndHorizontal();
if (autoPlay)
{
float diff = Time.realtimeSinceStartup - startTime;
diff *= speed;
m_SliderValue = diff / length;
foreach (var kvp in clipsDic)
{
int selectIndex = clipIndexDic[kvp.Key];
AnimationClip clip = kvp.Value[selectIndex];
float time = clip.length * m_SliderValue;
clip.SampleAnimation(kvp.Key, time);
}
if (diff >= length)
{
startTime = Time.realtimeSinceStartup;
if (!loop)
{
autoPlay = false;
isPlaying = false;
}
}
}
Repaint();//解决Editor面板不实时刷新的问题
}
}
}