sk-client/Assets/Scripts/AnimatorEvent/Editor/AnimatorEventEditor.cs

1194 lines
31 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using UnityEngine;
using UnityEditor;
using UnityEditorInternal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEditor.Animations;
using State = UnityEditor.Animations.AnimatorState;
using AnimatorTransitionBase = UnityEditor.Animations.AnimatorTransitionBase;
using AnimatorController = UnityEditor.Animations.AnimatorController;
using StateMachine = UnityEditor.Animations.AnimatorStateMachine;
using AnimatorControllerLayer = UnityEditor.Animations.AnimatorControllerLayer;
using GameLogic;
namespace Game {
public class AnimatorEventEditor : EditorWindow {
#region singleton
private static AnimatorEventEditor ms_instance = null;
public static AnimatorEventEditor instance {
get {
return ms_instance;
}
}
#endregion
#region private members
private AnimatorEventHandler m_handler = null;
private string[] m_animatorLayers = null;
private Dictionary<string, State[]> m_animatorStates = null;
private Dictionary<State, string> m_stateFullNames = null;
private Dictionary<StateMachine, string> m_stateMachineFullNames = null;
private Dictionary<int, AnimatorTransitionBase[]> m_animatorTransitions = null;
private int m_selectedLayerIndex = -1;
private int m_selectedStateIndex = -1;
private MsgEvent m_selectedEvent = null;
private bool m_isDataChanged = false;
private bool m_isSimulating = false;
private float m_playbackTime = 0f;
// 为了接入wwise的akwwisecomponetpicker而需要的参数
private SerializedObject m_AkSerializeObject = null;
private SerializedProperty[] m_AkValueProperty = null;
private string[] shakeTypeStrings = null;
#endregion
#region public properties
public AnimatorEventHandler handler {
set {
if (m_handler == value)
return;
_CheckDataSaved();
isSimulating = false;
m_handler = value;
_OnHandlerChanged();
}
get {
return m_handler;
}
}
#endregion
#region private properties
AnimatorController animatorController {
get {
if (handler == null)
return null;
if (handler.animator == null)
return null;
return (AnimatorController)handler.animator.runtimeAnimatorController;
}
}
int selectedLayerIndex {
set {
if (m_selectedLayerIndex == value)
return;
m_selectedLayerIndex = value;
_OnSelectedLayerChanged();
}
get {
return m_selectedLayerIndex;
}
}
string selectedLayerName {
get {
if (m_animatorLayers == null)
return null;
if (selectedLayerIndex < 0)
return null;
if (selectedLayerIndex >= m_animatorLayers.Length)
return null;
return m_animatorLayers[selectedLayerIndex];
}
}
State[] animatorStatesInSelectedLayer {
get {
if (m_animatorStates == null)
return null;
if (selectedLayerName == null)
return null;
State[] states;
if (!m_animatorStates.TryGetValue(selectedLayerName, out states))
return null;
return states;
}
}
string[] animatorStatesNameInSelectedLayer {
get {
if (animatorStatesInSelectedLayer == null)
return null;
string[] statesName = new string[animatorStatesInSelectedLayer.Length];
for (int i = 0; i < animatorStatesInSelectedLayer.Length; ++i)
statesName[i] = animatorStatesInSelectedLayer[i].name;
return statesName;
}
}
int selectedStateIndex {
set {
if (m_selectedStateIndex == value)
return;
m_selectedStateIndex = value;
_OnSelectedStateChanged();
}
get {
return m_selectedStateIndex;
}
}
State selectedState {
get {
if (animatorStatesInSelectedLayer == null)
return null;
if (selectedStateIndex < 0)
return null;
if (selectedStateIndex >= animatorStatesInSelectedLayer.Length)
return null;
return animatorStatesInSelectedLayer[selectedStateIndex];
}
}
float selectedStateLength {
get {
if (selectedState == null)
return 0;
Motion motion = selectedState.motion;
if (motion == null)
return 0;
return motion.averageDuration;
}
}
int selectedStateFrames {
get {
return Mathf.RoundToInt(selectedStateLength * 30);
}
}
List<MsgEvent> animatorEventsInSelectedState {
get {
if (handler == null)
return null;
if (handler.animatorEventData == null)
return null;
if (selectedState == null)
return null;
handler.animatorEventData.MakeSureEventList(GetUniqueNameHash(selectedState));
return handler.animatorEventData.GetEventList(GetUniqueNameHash(selectedState), selectedLayerIndex);
}
}
int GetUniqueNameHash(State state)
{
int hash = 0;
if (m_stateFullNames.ContainsKey(state))
{
hash = Animator.StringToHash(m_stateFullNames[state]);
}
else
{
hash = state.nameHash;
}
return hash;
}
bool RequestAddEvent(int stateHash, MsgEvent addEvent)
{
if (addEvent == null)
return false;
if (handler == null)
return false;
if (handler.animatorEventData == null)
return false;
return handler.animatorEventData.AddEvent(stateHash, addEvent);
}
bool RequestRemoveEvent(int stateHash, MsgEvent deleteEvent)
{
if (deleteEvent == null)
return false;
if (handler == null)
return false;
if (handler.animatorEventData == null)
return false;
return handler.animatorEventData.RemoveEvent(stateHash, deleteEvent);
}
MsgEvent selectedEvent {
set {
if (m_selectedEvent == value)
return;
m_selectedEvent = value;
_OnSelectedEventChanged();
}
get {
return m_selectedEvent;
}
}
bool isSimulating
{
set {
if (m_isSimulating == value)
return;
m_isSimulating = value;
if (m_isSimulating) {
_OnEnterSimulatingState();
}
else {
_OnLeaveSimulatingState();
}
}
get {
return m_isSimulating;
}
}
// In range [0, 1]
float playbackTime {
set {
if (value == 1f)
m_playbackTime = 1f;
else
m_playbackTime = Mathf.Repeat(value, 1f);
Repaint();
}
get {
return m_playbackTime;
}
}
#endregion
public static void ShowWindow() {
GetWindow<AnimatorEventEditor>();
}
void OnEnable() {
ms_instance = this;
isSimulating = false;
titleContent.text = "编辑动画器事件"; // title
minSize = new Vector2(950, 320);
m_AkSerializeObject = new SerializedObject(this);
m_AkValueProperty = new SerializedProperty[1];
m_AkValueProperty[0] = m_AkSerializeObject.FindProperty("valueGuid.Array");
shakeTypeStrings = new string[4];
shakeTypeStrings[0] = "全方向随机";
shakeTypeStrings[1] = "上下震动";
shakeTypeStrings[2] = "左右震动";
shakeTypeStrings[3] = "前后震动";
}
void OnDisable() {
isSimulating = false;
handler = null;
ms_instance = null;
}
#region OnGUI
void OnGUI() {
if (animatorController == null)
{
if (handler != null && handler.animator != null && handler.animator.runtimeAnimatorController==null)
{
ShowNotification(new GUIContent("该Animator没有控制器请先选择控制器."));
}
else
{
ShowNotification(new GUIContent("请先选择一个有Animator和AnimatorEventHandler组件的物件."));
}
return;
}
RemoveNotification();
GUILayout.BeginVertical();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
_DrawLayersPanel();
GUILayout.Space(10);
_DrawStatesPanel();
GUILayout.Space(10);
_DrawStateInformation();
GUILayout.EndHorizontal();
GUILayout.Space(10);
GUILayout.EndVertical();
if (!Application.isPlaying)
m_isSimulating = false;
if (isSimulating) {
_SimulateStateStatus();
}
else {
_SyncStateStatus();
}
}
private Vector2 m_LayerScrollPos;
void _DrawLayersPanel() {
GUILayout.BeginVertical(GUILayout.Width(150));
if (animatorController != null && m_animatorLayers != null) {
GUILayout.Label(string.Format("动画器[{0}]有{1}个动画层。", animatorController.name, m_animatorLayers.Length));
GUILayout.BeginVertical("Box");
m_LayerScrollPos = GUILayout.BeginScrollView(m_LayerScrollPos);
selectedLayerIndex = GUILayout.SelectionGrid(selectedLayerIndex, m_animatorLayers, 1);
GUILayout.EndScrollView();
GUILayout.EndVertical();
}
else {
GUILayout.Label("此动画器无动画层!");
}
GUILayout.EndVertical();
}
private Vector2 m_StateScrollPos;
void _DrawStatesPanel() {
GUILayout.BeginVertical(GUILayout.Width(200));
if (selectedLayerName != null && animatorStatesNameInSelectedLayer != null) {
GUILayout.Label(string.Format("动画层[{0}]有{1}个动画状态。", selectedLayerName, animatorStatesNameInSelectedLayer.Length));
GUILayout.BeginVertical("Box");
m_StateScrollPos = GUILayout.BeginScrollView(m_StateScrollPos);
selectedStateIndex = GUILayout.SelectionGrid(selectedStateIndex, animatorStatesNameInSelectedLayer, 1);
GUILayout.EndScrollView();
GUILayout.EndVertical();
}
else {
GUILayout.Label("此动画层无动画状态。");
}
GUILayout.EndVertical();
}
void _DrawStateInformation() {
GUILayout.BeginVertical();
_DrawStateLabel();
GUILayout.Space(10);
GUILayout.BeginHorizontal();
GUILayout.Space(10);
_DrawStateTimeline();
GUILayout.Space(10);
GUILayout.EndHorizontal();
GUILayout.Space(10);
_DrawToolsPanel();
GUILayout.Space(10);
_DrawEventPanel();
GUILayout.EndVertical();
}
void _DrawStateLabel() {
if (selectedState == null) {
GUILayout.Label("请选择动画状态。");
return;
}
int totalEventCount = 0;
int effectEventCount = 0;
int wwiseEventCount = 0;
int cameraShakeEventCount = 0;
int msgEventCount = 0;
var listEvents = animatorEventsInSelectedState;
if (listEvents != null)
{
totalEventCount = listEvents.Count;
for (int i = 0; i < totalEventCount; ++i) {
switch (listEvents[i].type)
{
case AnimatorEventType.Msg:
++msgEventCount;
break;
default:
break;
}
}
}
GUILayout.Label(
string.Format(
"动画状态[{0}]{1}帧/{2}秒)共有{3}个动画事件,其中,{4}个Msg事件。请不要再黄线之后添加事件。",
selectedState.name,
selectedStateFrames,
selectedStateLength.ToString("0.00"),
totalEventCount,
msgEventCount));
}
void _DrawStateTimeline() {
Rect rect = GUILayoutUtility.GetRect(500, 10000, 50, 50);
int timelineId = GUIUtility.GetControlID("TimelineControl".GetHashCode(), FocusType.Passive, rect);
Rect thumbRect = new Rect(rect.x + rect.width * playbackTime - 5, rect.y + 2, 10, 10);
Event e = Event.current;
switch (e.type) {
case EventType.Repaint:
Rect lineRect = new Rect(rect.x, rect.y + 10, rect.width, 1.5f);
_DrawTimeLine(lineRect);
GUI.skin.horizontalSliderThumb.Draw(thumbRect, new GUIContent(), timelineId);
break;
case EventType.MouseDown:
if (thumbRect.Contains(e.mousePosition)) {
GUIUtility.hotControl = timelineId;
e.Use();
}
else {
if (GUIUtility.hotControl == timelineId) {
GUIUtility.hotControl = 0;
}
}
break;
case EventType.MouseUp:
if (GUIUtility.hotControl == timelineId) {
GUIUtility.hotControl = 0;
e.Use();
}
break;
case EventType.MouseDrag:
if (GUIUtility.hotControl == timelineId) {
Vector2 guiPos = e.mousePosition;
float clampedX = Mathf.Clamp(guiPos.x, rect.x, rect.x + rect.width);
playbackTime = (clampedX - rect.x) / rect.width;
e.Use();
}
break;
default:
break;
}
var listEvent = animatorEventsInSelectedState;
if (listEvent != null)
{
for (int i = 0; i < listEvent.Count; ++i)
{
_DrawEventKey(rect, listEvent[i]);
}
}
if (selectedState != null)
{
_DrawMinimumExitTime(rect, GetMinimumExitTimeForState(GetUniqueNameHash(selectedState)));
}
}
private Material m_lineMaterial = null;
void _DrawTimeLine(Rect rect) {
if (Event.current.type != EventType.Repaint) {
return;
}
if (selectedStateFrames <= 0)
return;
if (m_lineMaterial == null) {
m_lineMaterial = new Material(Shader.Find("Diffuse"));
}
if (m_lineMaterial != null)
m_lineMaterial.SetPass(0);
GL.Begin(GL.LINES);
GL.Color(new Color(1f, 1f, 1f, 0.75f));
_DrawHorizontalLine(rect.x, rect.y, rect.width);
_DrawHorizontalLine(rect.x, rect.y + 25, rect.width);
float frameWidth = rect.width / selectedStateFrames;
for (int i = 0; i <= selectedStateFrames; ++i) {
if (i % 10 == 0) {
_DrawVerticalLine(rect.x + i * frameWidth, rect.y, 15);
}
else if (i % 5 == 0) {
_DrawVerticalLine(rect.x + i * frameWidth, rect.y, 10);
}
else {
_DrawVerticalLine(rect.x + i * frameWidth, rect.y, 5);
}
}
GL.Color(new Color(1f, 1f, 1f, 0.75f));
_DrawVerticalLine(rect.x + rect.width * playbackTime, rect.y, 20);
GL.End();
}
void _DrawHorizontalLine(float x, float y, float width) {
GL.Vertex3(x, y, 0);
GL.Vertex3(x + width, y, 0);
}
void _DrawVerticalLine(float x, float y, float height) {
GL.Vertex3(x, y, 0);
GL.Vertex3(x, y + height, 0);
}
void _AddEventKey(object obj) {
MsgEvent newKey = null;
AnimatorEventType eventType = (AnimatorEventType)obj;
switch (eventType) {
case AnimatorEventType.Msg:
newKey = new MsgEvent();
newKey.name = "新建Msg事件";
break;
default:
break;
}
if (newKey != null && animatorEventsInSelectedState != null) {
newKey.layer = selectedLayerIndex;
newKey.normalizedTime = playbackTime;
RequestAddEvent(GetUniqueNameHash(selectedState), newKey);
m_isDataChanged = true;
selectedEvent = newKey;
}
}
void _DeleteEventKey() {
if (selectedEvent == null)
return;
if (selectedState == null)
return;
if (animatorEventsInSelectedState == null)
return;
int selectedIndex = animatorEventsInSelectedState.IndexOf(selectedEvent);
if (selectedIndex < 0)
return;
int stateHash = GetUniqueNameHash(selectedState);
RequestRemoveEvent(stateHash, selectedEvent);
selectedEvent = null;
List<MsgEvent> listEvent = animatorEventsInSelectedState;
m_isDataChanged = true;
if (listEvent.Count > 0)
{
if (selectedIndex >= listEvent.Count)
selectedIndex = listEvent.Count - 1;
selectedEvent = listEvent[selectedIndex];
}
}
void _DrawMinimumExitTime(Rect rect, float minimumExitTime)
{
float keyTime = minimumExitTime;
Rect keyRect = new Rect(rect.x + rect.width * keyTime - 3, rect.y, 6, 60);
int eventKeyCtrl = 999;
Event e = Event.current;
switch (e.type)
{
case EventType.Repaint:
Color savedColor = GUI.color;
GUI.color = Color.yellow;
GUI.skin.button.Draw(keyRect, new GUIContent(), eventKeyCtrl);
GUI.color = savedColor;
if (m_hotEventKey == eventKeyCtrl || (m_hotEventKey == 0 && keyRect.Contains(e.mousePosition)))
{
string labelString = string.Format(
"{0}@{1}", "exittime", minimumExitTime.ToString("0.0000"));
Vector2 size = EditorStyles.largeLabel.CalcSize(new GUIContent(labelString));
Rect infoRect = new Rect(rect.x + rect.width * keyTime - size.x, rect.y, size.x, size.y);
savedColor = GUI.color;
GUI.color = Color.yellow;
EditorStyles.largeLabel.Draw(infoRect, new GUIContent(labelString), eventKeyCtrl);
GUI.color = savedColor;
}
break;
}
}
private int m_hotEventKey = 0;
void _DrawEventKey(Rect rect, MsgEvent animatorEvent) {
if (animatorEvent.layer == -1)
{
animatorEvent.layer = selectedLayerIndex;
}
float keyTime = animatorEvent.normalizedTime;
Rect keyRect = new Rect(rect.x + rect.width * keyTime - 3, rect.y + 25, 6, 18);
int eventKeyCtrl = animatorEvent.GetHashCode();
Event e = Event.current;
switch (e.type) {
case EventType.Repaint:
Color savedColor = GUI.color;
GUI.color = Color.gray;
if (selectedEvent == animatorEvent)
GUI.color = Color.red;
GUI.skin.button.Draw(keyRect, new GUIContent(), eventKeyCtrl);
GUI.color = savedColor;
if (m_hotEventKey == eventKeyCtrl || (m_hotEventKey == 0 && keyRect.Contains(e.mousePosition))) {
string labelString = string.Format(
"{0}@{1}", animatorEvent.name, animatorEvent.normalizedTime.ToString("0.0000"));
Vector2 size = EditorStyles.largeLabel.CalcSize(new GUIContent(labelString));
Rect infoRect = new Rect(rect.x + rect.width * keyTime - size.x / 2, rect.y + 50, size.x, size.y);
EditorStyles.largeLabel.Draw(infoRect, new GUIContent(labelString), eventKeyCtrl);
}
break;
case EventType.MouseDown:
if (keyRect.Contains(e.mousePosition)) {
// 如果当前聚焦归一化时间编辑框,该编辑框的数据不会刷新。所以在选中事件时,清空当前聚焦。
EditorGUI.FocusTextInControl("");
m_hotEventKey = eventKeyCtrl;
selectedEvent = animatorEvent;
playbackTime = selectedEvent.normalizedTime;
e.Use();
}
break;
case EventType.MouseDrag:
if (m_hotEventKey == eventKeyCtrl) {
if (e.button == 0) {
Vector2 guiPos = e.mousePosition;
float clampedX = Mathf.Clamp(guiPos.x, rect.x, rect.x + rect.width);
animatorEvent.normalizedTime = (clampedX - rect.x) / rect.width;
m_isDataChanged = true;
selectedEvent = animatorEvent;
playbackTime = selectedEvent.normalizedTime;
}
e.Use();
}
break;
case EventType.MouseUp:
if (m_hotEventKey == eventKeyCtrl) {
m_hotEventKey = 0;
e.Use();
}
break;
}
}
void _DrawToolsPanel() {
GUILayout.BeginHorizontal();
EditorGUI.BeginDisabledGroup(Application.isPlaying == false);
string buttonText = isSimulating ? "关闭运行时编辑" : "开启运行时编辑";
if (GUILayout.Button(buttonText, GUILayout.Width(120))) {
isSimulating = !isSimulating;
if (!isSimulating && handler != null && handler.animator != null)
{
handler.animator.Update(0);
}
}
EditorGUI.EndDisabledGroup();
GUILayout.FlexibleSpace();
if (GUILayout.Button("添加事件", GUILayout.Width(80))) {
GenericMenu menu = new GenericMenu();
menu.AddItem(new GUIContent("Msg事件"), false, _AddEventKey, AnimatorEventType.Msg);
menu.ShowAsContext();
}
EditorGUI.BeginDisabledGroup(selectedEvent == null);
if (GUILayout.Button("删除事件", GUILayout.Width(80))) {
if (selectedEvent != null)
_DeleteEventKey();
}
EditorGUI.EndDisabledGroup();
EditorGUI.BeginDisabledGroup(false);
if (GUILayout.Button("清除冗余", GUILayout.Width(80)))
{
List<int> stateHashs = new List<int>();
foreach (var e in m_animatorStates)
{
for (int i = 0; i < e.Value.Length; ++i)
{
stateHashs.Add(GetUniqueNameHash(e.Value[i]));
}
}
}
EditorGUI.EndDisabledGroup();
GUILayout.Space(20);
EditorGUI.BeginDisabledGroup(m_isDataChanged == false);
if (GUILayout.Button("保存prefab", GUILayout.Width(80))) {
m_isDataChanged = false;
TestPrefabApply(handler.gameObject);
EditorUtility.SetDirty(handler.gameObject);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
if (GUILayout.Button("还原prefab", GUILayout.Width(80))) {
m_isDataChanged = false;
if (handler != null)
{
PrefabUtility.RevertPrefabInstance(handler.gameObject);
}
}
EditorGUI.EndDisabledGroup();
GUILayout.EndHorizontal();
if (selectedState == null)
return;
GUILayout.BeginHorizontal();
int slotIndex = 0;
List<MsgEvent> listBase = new List<MsgEvent>(animatorEventsInSelectedState);
List<MsgEvent> changedBase = new List<MsgEvent>();
List<string> listNormal = new List<string>();
int paramNum = 0;
while (listBase != null && listBase.Count > 0)
{
int index = 0;
for (int i = 1; i < listBase.Count; ++i)
{
if (listBase[i].normalizedTime < listBase[index].normalizedTime)
index = i;
}
if (listBase[index] == selectedEvent)
slotIndex = listNormal.Count;
changedBase.Add(listBase[index]);
listNormal.Add(string.Format("{0}: {1} - {2} - {3}", (paramNum++), listBase[index].type, listBase[index].name, listBase[index].normalizedTime));
listBase.RemoveAt(index);
}
int selectIndex = EditorGUILayout.Popup("事件列表", slotIndex, listNormal.ToArray());
if ((selectIndex >= 0 && selectIndex < changedBase.Count) && (selectIndex != slotIndex || selectedEvent == null))
{
selectedEvent = changedBase[selectIndex];
}
GUILayout.EndHorizontal();
}
private Vector2 m_EventScrollPos;
void _DrawEventPanel() {
EditorGUI.BeginChangeCheck();
GUILayout.BeginVertical("Box");
m_EventScrollPos = GUILayout.BeginScrollView(m_EventScrollPos);
if (selectedEvent != null) {
switch (selectedEvent.type) {
case AnimatorEventType.Msg:
_DrawMsgEventPanel();
break;
}
}
else {
GUILayout.Label("请选择要编辑的事件。");
}
GUILayout.EndScrollView();
GUILayout.EndVertical();
if (EditorGUI.EndChangeCheck()) {
m_isDataChanged = true;
}
}
static readonly string RESOURCES_DIR = "Resources/Prefabs/";
static readonly string PREFAB_SUFFIX = ".prefab";
string _GetEffectPrefabPath(GameObject effectPrefab) {
if (effectPrefab == null)
return string.Empty;
string filePath = AssetDatabase.GetAssetPath(effectPrefab);
bool isUseResourcePath = true;
if (isUseResourcePath)
{
int index = filePath.IndexOf(RESOURCES_DIR);
if (index < 0)
return filePath;
index += RESOURCES_DIR.Length;
if (index > filePath.Length)
return filePath;
filePath = filePath.Substring(index);
}
return filePath;
}
List<string> getAllGameNames()
{
var games = Directory.GetDirectories(AppConst.GameResRealPath);
var gameNames = new List<string>();
for (int i = 0; i < games.Length; i++)
{
games[i] = Path.GetFileNameWithoutExtension(games[i]);
gameNames.Add(games[i]);
}
return gameNames;
}
void _DrawMsgEventPanel() {
if (handler == null) return;
MsgEvent msgEvent = (MsgEvent)selectedEvent;
if (msgEvent == null) return;
GUILayout.BeginVertical();
GUILayout.Label(string.Format("编辑Msg事件[{0}@{1}]", msgEvent.name, msgEvent.normalizedTime));
GUILayout.Space(10);
msgEvent.name = EditorGUILayout.TextField("事件名称", msgEvent.name);
msgEvent.normalizedTime = EditorGUILayout.FloatField("归一化时间", msgEvent.normalizedTime);
msgEvent.normalizedTime = Mathf.Clamp(msgEvent.normalizedTime, 0, 1f);
msgEvent.msgFunction = EditorGUILayout.TextField("响应函数名称", msgEvent.msgFunction);
msgEvent.msgParams = EditorGUILayout.TextField("参数", msgEvent.msgParams);
GUILayout.EndVertical();
}
#endregion
public static void TestPrefabApply(GameObject selectGo)
{
if (selectGo == null)
{
Debug.LogError("请选中需要Apply的Prefab实例");
return;
}
PrefabType pType = EditorUtility.GetPrefabType(selectGo);
if (pType != PrefabType.PrefabInstance)
{
Debug.LogError("选中的实例不是Prefab实例");
return;
}
//这里必须获取到prefab实例的根节点否则ReplacePrefab保存不了
GameObject prefabGo = GetPrefabInstanceParent(selectGo);
UnityEngine.Object prefabAsset = null;
if (prefabGo != null)
{
prefabAsset = PrefabUtility.GetPrefabParent(prefabGo);
if (prefabAsset != null)
{
PrefabUtility.ReplacePrefab(prefabGo, prefabAsset, ReplacePrefabOptions.ConnectToPrefab);
}
}
AssetDatabase.SaveAssets();
}
//遍历获取prefab节点所在的根prefab节点
static GameObject GetPrefabInstanceParent(GameObject go)
{
if (go == null)
{
return null;
}
PrefabType pType = EditorUtility.GetPrefabType(go);
if (pType != PrefabType.PrefabInstance)
{
return null;
}
if (go.transform.parent == null)
{
return go;
}
pType = EditorUtility.GetPrefabType(go.transform.parent.gameObject);
if (pType != PrefabType.PrefabInstance)
{
return go;
}
return GetPrefabInstanceParent(go.transform.parent.gameObject);
}
void _CheckDataSaved() {
if (m_isDataChanged == false)
return;
if (handler == null)
return;
if (animatorController == null)
return;
string message = string.Format("动画器[{0}]的事件数据发生了变化,是否保存?", animatorController.name);
bool isSave = EditorUtility.DisplayDialog("是否保存动画器事件?", message, "保存", " 不保存");
if (isSave)
{
TestPrefabApply(handler.gameObject);
EditorUtility.SetDirty(handler.gameObject);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
m_isDataChanged = false;
}
void _OnHandlerChanged() {
m_animatorLayers = null;
m_animatorStates = null;
m_selectedLayerIndex = -1;
m_selectedStateIndex = -1;
selectedEvent = null;
if (handler == null)
return;
if (handler.animator == null)
return;
AnimatorController animatorController = (AnimatorController)handler.animator.runtimeAnimatorController;
if (animatorController == null)
return;
m_animatorLayers = new string[animatorController.layers.Length];
m_animatorStates = new Dictionary<string, State[]>();
m_stateFullNames = new Dictionary<State, string>();
m_stateMachineFullNames = new Dictionary<AnimatorStateMachine, string>();
m_animatorTransitions = new Dictionary<int, AnimatorTransitionBase[]>();
for (int i = 0; i < animatorController.layers.Length; ++i) {
AnimatorControllerLayer layer = animatorController.layers[i];
m_animatorLayers[i] = layer.name;
List<State> stateList = _GetStatesRecursive(layer.stateMachine);
m_animatorStates.Add(layer.name, stateList.ToArray());
Dictionary<int, AnimatorTransitionBase[]> transDic = _GetTransitionsRecursive(layer.stateMachine);
foreach (var e in transDic)
{
m_animatorTransitions[e.Key] = e.Value;
}
}
selectedLayerIndex = 0;
}
float GetMinimumExitTimeForState(int stateHash)
{
float exitTime = 1;
if (m_animatorTransitions == null)
return exitTime;
AnimatorTransitionBase[] trans = null;
if (!m_animatorTransitions.TryGetValue(stateHash, out trans) || trans == null)
return exitTime;
for (int j = 0; j < trans.Length; ++j)
{
AnimatorStateTransition stateTrans = trans[j] as AnimatorStateTransition;
if (stateTrans == null)
continue;
if (stateTrans.hasExitTime && stateTrans.exitTime < exitTime)
{
exitTime = stateTrans.exitTime;
}
}
return exitTime;
}
Dictionary<int, AnimatorTransitionBase[]> _GetTransitionsRecursive(StateMachine stateMachine)
{
Dictionary<int, AnimatorTransitionBase[]> dic = new Dictionary<int, AnimatorTransitionBase[]>();
for (int i = 0; i < stateMachine.states.Length; ++i)
{
State s = stateMachine.states[i].state;
dic[GetUniqueNameHash(s)] = s.transitions;
}
for (int i = 0; i < stateMachine.stateMachines.Length; ++i)
{
foreach (var e in _GetTransitionsRecursive(stateMachine.stateMachines[i].stateMachine))
{
dic[e.Key] = e.Value;
}
}
return dic;
}
List<State> _GetStatesRecursive(StateMachine stateMachine) {
if (!m_stateMachineFullNames.ContainsKey(stateMachine))
{
m_stateMachineFullNames.Add(stateMachine, stateMachine.name);
}
List<State> list = new List<State>();
list.AddRange(_GetAnimatorStates(stateMachine));
for (int i = 0; i < list.Count; ++i)
{
if (!m_stateFullNames.ContainsKey(list[i]))
{
m_stateFullNames.Add(list[i], m_stateMachineFullNames[stateMachine] + "." + list[i].name);
}
}
for (int i = 0; i < stateMachine.stateMachines.Length; ++i)
{
StateMachine childMachine = stateMachine.stateMachines[i].stateMachine;
if (!m_stateMachineFullNames.ContainsKey(childMachine))
{
m_stateMachineFullNames.Add(childMachine, m_stateMachineFullNames[stateMachine] + "." + childMachine.name);
}
list.AddRange(_GetStatesRecursive(stateMachine.stateMachines[i].stateMachine));
}
return list;
}
State[] _GetAnimatorStates(StateMachine stateMachine) {
State[] array = new State[stateMachine.states.Length];
for (int i = 0; i < stateMachine.states.Length; ++i) {
array[i] = stateMachine.states[i].state;
}
return array;
}
void _OnSelectedLayerChanged() {
selectedEvent = null;
selectedStateIndex = 0;
Repaint();
}
void _OnSelectedStateChanged() {
selectedEvent = null;
playbackTime = 0f;
Repaint();
}
void _OnSelectedEventChanged() {
if (!Application.isPlaying)
return;
if (!isSimulating)
return;
if (m_selectedEvent == null)
return;
_SimulateStateStatus();
}
void _OnEnterSimulatingState() {
if (!Application.isPlaying)
return;
if (handler != null)
handler.enabled = false;
if (handler.animator != null)
handler.animator.speed = 0f;
_OnSelectedEventChanged();
}
void _OnLeaveSimulatingState() {
if (!Application.isPlaying)
return;
if (handler != null) {
handler.enabled = true;
}
if (handler.animator != null)
handler.animator.speed = 1f;
}
void _SimulateStateStatus() {
if (!Application.isPlaying)
return;
if (handler == null)
return;
if (handler.animator != null) {
AnimatorControllerLayer ctllayer = animatorController.layers[selectedLayerIndex];
int playLayer = ctllayer.syncedLayerIndex < 0 ? selectedLayerIndex : ctllayer.syncedLayerIndex;
int nameHash = selectedState == null ? -1 : selectedState.nameHash;
handler.animator.Play(nameHash, playLayer, playbackTime);
}
}
void _SyncStateStatus() {
if (!Application.isPlaying)
return;
if (handler == null)
return;
if (animatorStatesInSelectedLayer == null)
return;
AnimatorStateInfo currentStateInfo = handler.GetCurrentStateInfo(selectedLayerIndex);
float _stateNormalizedTime = currentStateInfo.normalizedTime;
for (int i = 0; i < animatorStatesInSelectedLayer.Length; ++i) {
if (GetUniqueNameHash(animatorStatesInSelectedLayer[i]) != currentStateInfo.fullPathHash)
continue;
selectedStateIndex = i;
playbackTime = _stateNormalizedTime;
}
}
}
}