mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
Revert "[-] Remove Thirdly of Animation"
This reverts commit cb2b9331cf
.
This commit is contained in:
8
Assets/TEngine/Thirdly/Animation.meta
Normal file
8
Assets/TEngine/Thirdly/Animation.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0db55501a091a6e429dd80459f36b6af
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
9
Assets/TEngine/Thirdly/Animation/Editor.meta
Normal file
9
Assets/TEngine/Thirdly/Animation/Editor.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b94472036d46ad5498116fcc1cbf4dfe
|
||||||
|
folderAsset: yes
|
||||||
|
timeCreated: 1510262153
|
||||||
|
licenseType: Store
|
||||||
|
DefaultImporter:
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
136
Assets/TEngine/Thirdly/Animation/Editor/AnimationClipUtil.cs
Normal file
136
Assets/TEngine/Thirdly/Animation/Editor/AnimationClipUtil.cs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
/*------------------------------------------------------------------------------
|
||||||
|
Original Author: Pikachuxxxx
|
||||||
|
Adapted By: Brandon Lyman
|
||||||
|
This script is an adaptation of Pikachuxxxx's utiltiy to reverse an animation
|
||||||
|
clip in Unity. Please find the original Github Gist here:
|
||||||
|
https://gist.github.com/8101da6d14a5afde80c7c180e3a43644.git
|
||||||
|
ABSOLUTELY ALL CREDIT FOR THIS SCRIPT goes to Pikachuxxxx. Thank you so much for
|
||||||
|
your original script!
|
||||||
|
Unfortunately, their method that utilizes
|
||||||
|
"AnimationUtility.GetAllCurves()" is obsolete, according to the official
|
||||||
|
unity documentation:
|
||||||
|
https://docs.unity3d.com/ScriptReference/AnimationUtility.GetAllCurves.html
|
||||||
|
The editor suggests using "AnimationUtility.GetCurveBindings()" in its stead,
|
||||||
|
and this script reveals how that can be accomplished as it is slightly
|
||||||
|
different from the original methodology. I also added in some logic to
|
||||||
|
differentiate between the original clip and the new clip being created, as
|
||||||
|
I experienced null reference exceptions after the original "ClearAllCurves()"
|
||||||
|
call. Additionally, I placed the script's logic in a ScriptableWizard class to
|
||||||
|
fit the needs for my project. For more information on ScriptableWizards, please
|
||||||
|
refer to this Unity Learn Tutorial:
|
||||||
|
https://learn.unity.com/tutorial/creating-basic-editor-tools#5cf6c8f2edbc2a160a8a0951
|
||||||
|
Hope this helps and please comment with any questions. Thanks!
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
//using static DG.DemiEditor.DeGUIKey;
|
||||||
|
|
||||||
|
public class SpiteAnimationClip : ScriptableWizard
|
||||||
|
{
|
||||||
|
public string NewFileName = "";
|
||||||
|
|
||||||
|
public float BeginTime = 0;
|
||||||
|
|
||||||
|
public float EndTime = 1;
|
||||||
|
|
||||||
|
[MenuItem("Tools/SplitAnimationClip...")]
|
||||||
|
private static void SplitAnimationClipShow()
|
||||||
|
{
|
||||||
|
ScriptableWizard.DisplayWizard<SpiteAnimationClip>("SpiteAnimationClip...", "splite");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnWizardCreate()
|
||||||
|
{
|
||||||
|
string directoryPath =
|
||||||
|
Path.GetDirectoryName(AssetDatabase.GetAssetPath(Selection.activeObject));
|
||||||
|
string fileName =
|
||||||
|
Path.GetFileName(AssetDatabase.GetAssetPath(Selection.activeObject));
|
||||||
|
string fileExtension =
|
||||||
|
Path.GetExtension(AssetDatabase.GetAssetPath(Selection.activeObject));
|
||||||
|
fileName = fileName.Split('.')[0];
|
||||||
|
|
||||||
|
string copiedFilePath = "";
|
||||||
|
if (NewFileName != null && NewFileName != "")
|
||||||
|
{
|
||||||
|
copiedFilePath = directoryPath + Path.DirectorySeparatorChar + NewFileName + fileExtension;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
copiedFilePath = directoryPath + Path.DirectorySeparatorChar + fileName + $"_split_{BeginTime}_{EndTime}" + fileExtension;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationClip originalClip = GetSelectedClip();
|
||||||
|
|
||||||
|
AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(Selection.activeObject), copiedFilePath);
|
||||||
|
|
||||||
|
AnimationClip reversedClip = (AnimationClip)AssetDatabase.LoadAssetAtPath(copiedFilePath, typeof(AnimationClip));
|
||||||
|
|
||||||
|
if (originalClip == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float clipLength = originalClip.length;
|
||||||
|
EditorCurveBinding[] curveBindings = AnimationUtility.GetCurveBindings(originalClip);
|
||||||
|
Debug.Log(curveBindings.Length);
|
||||||
|
reversedClip.ClearCurves();
|
||||||
|
float timeOffset = -1;
|
||||||
|
foreach (EditorCurveBinding binding in curveBindings)
|
||||||
|
{
|
||||||
|
AnimationCurve curve = AnimationUtility.GetEditorCurve(originalClip, binding);
|
||||||
|
var keys = new List<Keyframe>();// curve.keys;
|
||||||
|
int keyCount = curve.keys.Length;
|
||||||
|
for (int i = 0; i < keyCount; i++)
|
||||||
|
{
|
||||||
|
Keyframe K = curve.keys[i];
|
||||||
|
|
||||||
|
if (K.time >= BeginTime && K.time <= EndTime)
|
||||||
|
{
|
||||||
|
if (timeOffset < 0)
|
||||||
|
{
|
||||||
|
timeOffset = K.time;
|
||||||
|
}
|
||||||
|
K.time = K.time - timeOffset;
|
||||||
|
keys.Add(K);
|
||||||
|
Debug.LogError("time " + clipLength + " index " + i + " time " + K.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
curve.keys = keys.ToArray() ;
|
||||||
|
reversedClip.SetCurve(binding.path, binding.type, binding.propertyName, curve);
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimationEvent[] events = AnimationUtility.GetAnimationEvents(originalClip);
|
||||||
|
|
||||||
|
var eventsList= new List<AnimationEvent>();
|
||||||
|
if (events.Length > 0)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < events.Length; i++)
|
||||||
|
{
|
||||||
|
var eventTemp = events[i];
|
||||||
|
if (eventTemp.time <= BeginTime && eventTemp.time >= EndTime)
|
||||||
|
{
|
||||||
|
eventTemp.time = eventTemp.time - timeOffset;
|
||||||
|
eventsList.Add(eventTemp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnimationUtility.SetAnimationEvents(reversedClip, eventsList.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log("[[ReverseAnimationClip.cs]] Successfully reversed " +
|
||||||
|
"animation clip " + fileName + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
private AnimationClip GetSelectedClip()
|
||||||
|
{
|
||||||
|
Object[] clips = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets);
|
||||||
|
if (clips.Length > 0)
|
||||||
|
{
|
||||||
|
return clips[0] as AnimationClip;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9368fbead1d3043419793a2c9c3ef030
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
@@ -0,0 +1,846 @@
|
|||||||
|
/// INFORMATION
|
||||||
|
///
|
||||||
|
/// Project: Chloroplast Games Framework
|
||||||
|
/// Game: Chloroplast Games Framework
|
||||||
|
/// Date: 02/05/2017
|
||||||
|
/// Author: Chloroplast Games
|
||||||
|
/// Web: http://www.chloroplastgames.com
|
||||||
|
/// Programmers: David Cuenca Diez
|
||||||
|
/// Description: Tool that allows change the path of hierarchy from a animation from an animation clip.
|
||||||
|
///
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// Local Namespace
|
||||||
|
namespace CGF.Editor.Tools
|
||||||
|
{
|
||||||
|
public class PathData
|
||||||
|
{
|
||||||
|
public string ClipName { get; }
|
||||||
|
public string CurrentPath { get; set; }
|
||||||
|
public string LastPath { get; set; }
|
||||||
|
public AnimationClip Clip { get; set; }
|
||||||
|
|
||||||
|
public EditorCurveBinding EditorCurve;
|
||||||
|
|
||||||
|
public PathData(string clipName, string currentPath, string lastPath, EditorCurveBinding editorCurve,AnimationClip clip)
|
||||||
|
{
|
||||||
|
ClipName = clipName;
|
||||||
|
CurrentPath = currentPath;
|
||||||
|
LastPath = lastPath;
|
||||||
|
EditorCurve = editorCurve;
|
||||||
|
Clip= clip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// \english
|
||||||
|
/// <summary>
|
||||||
|
/// Tool that allows change the path of hierarchy from a animation from an animation clip.
|
||||||
|
/// </summary>
|
||||||
|
/// \endenglish
|
||||||
|
/// \spanish
|
||||||
|
/// <summary>
|
||||||
|
/// Herramienta que permite canviar la ruta de la jerarqu<71>a de las animaciones de un clip de animaci<63>n.
|
||||||
|
/// </summary>
|
||||||
|
/// \endspanish
|
||||||
|
public class CGFAnimationHierarchyEditorTool : EditorWindow
|
||||||
|
{
|
||||||
|
|
||||||
|
#region Public Variables
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Private Variables
|
||||||
|
|
||||||
|
private enum TypeGameObject
|
||||||
|
{
|
||||||
|
|
||||||
|
None,
|
||||||
|
|
||||||
|
GameObject,
|
||||||
|
|
||||||
|
/*AnimationClip,
|
||||||
|
|
||||||
|
RuntimeAnimatorController*/
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private TypeGameObject _currentSelectionGameObject;
|
||||||
|
|
||||||
|
private int index;
|
||||||
|
|
||||||
|
private List<GameObject> _gameObjects;
|
||||||
|
|
||||||
|
private Animator _animatorObject;
|
||||||
|
|
||||||
|
private Animator _animatorObject2;
|
||||||
|
|
||||||
|
private List<PathData> _pathDataList;
|
||||||
|
|
||||||
|
private RuntimeAnimatorController _myruntime;
|
||||||
|
|
||||||
|
private List<AnimationClip> _currentAnimationClips;
|
||||||
|
|
||||||
|
private List<AnimationClip> _myanimationClips;
|
||||||
|
|
||||||
|
private List<string> _clipNames = new List<string>();
|
||||||
|
|
||||||
|
private string[] _modes = new string[] { "Path", "GameObject" };
|
||||||
|
|
||||||
|
private int _selectedMode = 0;
|
||||||
|
|
||||||
|
private string _replacePath = "";
|
||||||
|
|
||||||
|
private GameObject _replaceGameObject;
|
||||||
|
|
||||||
|
private string _replacementPath = "";
|
||||||
|
|
||||||
|
private GameObject _replacementGameObject;
|
||||||
|
|
||||||
|
private Vector2 scrollPosContent;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Main Methods
|
||||||
|
|
||||||
|
[MenuItem("Tools/Animation Hierarchy Editor Tool")]
|
||||||
|
private static void ShowWindow()
|
||||||
|
{
|
||||||
|
|
||||||
|
EditorWindow window = EditorWindow.GetWindow(typeof(CGFAnimationHierarchyEditorTool), false, "Animation Hierarchy Editor Tool", true);
|
||||||
|
|
||||||
|
window.minSize = new Vector2(1024, 250);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public CGFAnimationHierarchyEditorTool()
|
||||||
|
{
|
||||||
|
|
||||||
|
_currentSelectionGameObject = new TypeGameObject();
|
||||||
|
|
||||||
|
_currentSelectionGameObject = TypeGameObject.None;
|
||||||
|
|
||||||
|
_myanimationClips = new List<AnimationClip>();
|
||||||
|
|
||||||
|
_gameObjects = new List<GameObject>();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
ResetSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectionChange()
|
||||||
|
{
|
||||||
|
ResetSelection();
|
||||||
|
|
||||||
|
this.Repaint();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ResetSelection()
|
||||||
|
{
|
||||||
|
_myanimationClips.Clear();
|
||||||
|
|
||||||
|
_clipNames.Clear();
|
||||||
|
|
||||||
|
_animatorObject = null;
|
||||||
|
|
||||||
|
_myruntime = null;
|
||||||
|
|
||||||
|
_animatorObject2 = null;
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
if (Selection.activeGameObject is GameObject)
|
||||||
|
{
|
||||||
|
|
||||||
|
_currentSelectionGameObject = TypeGameObject.GameObject;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
_currentSelectionGameObject = TypeGameObject.None;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
DrawSeletedAnimator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawSeletedAnimator()
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_currentSelectionGameObject != TypeGameObject.GameObject)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_animatorObject2 = Selection.activeGameObject.GetComponent<Animator>();
|
||||||
|
|
||||||
|
if (_animatorObject2 == null)
|
||||||
|
{
|
||||||
|
_currentSelectionGameObject = TypeGameObject.None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_animatorObject = _animatorObject2;
|
||||||
|
|
||||||
|
if (_animatorObject2.runtimeAnimatorController == null)
|
||||||
|
{
|
||||||
|
_currentSelectionGameObject = TypeGameObject.None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_myruntime = _animatorObject2.runtimeAnimatorController;
|
||||||
|
|
||||||
|
if (_myruntime.animationClips.Length == 0)
|
||||||
|
{
|
||||||
|
_currentSelectionGameObject = TypeGameObject.None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (AnimationClip i in _myruntime.animationClips)
|
||||||
|
{
|
||||||
|
|
||||||
|
_myanimationClips.Add(i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_clipNames.Add("All Clips");
|
||||||
|
|
||||||
|
foreach (AnimationClip e in _myanimationClips)
|
||||||
|
{
|
||||||
|
|
||||||
|
_clipNames.Add(e.name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_myanimationClips.Count > 0)
|
||||||
|
{
|
||||||
|
_currentAnimationClips = _myanimationClips;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentAnimationClips = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
FillModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawGui()
|
||||||
|
{
|
||||||
|
|
||||||
|
bool animations = true;
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUILayout.Label("Selected Animator", GUILayout.Width(170));
|
||||||
|
|
||||||
|
GUI.enabled = false;
|
||||||
|
|
||||||
|
_animatorObject = ((Animator)EditorGUILayout.ObjectField(_animatorObject, typeof(Animator), true, GUILayout.Width(300)));
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
GUI.enabled = _currentSelectionGameObject == TypeGameObject.GameObject;
|
||||||
|
|
||||||
|
GUILayout.Label("Bulk Replace Mode");
|
||||||
|
|
||||||
|
_selectedMode = EditorGUILayout.Popup(_selectedMode, _modes);
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUI.enabled = false;
|
||||||
|
|
||||||
|
GUILayout.Label("Selected Animator Controller", GUILayout.Width(170));
|
||||||
|
|
||||||
|
_myruntime = ((RuntimeAnimatorController)EditorGUILayout.ObjectField(_myruntime, typeof(RuntimeAnimatorController), true, GUILayout.Width(300)));
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
GUI.enabled = _currentSelectionGameObject == TypeGameObject.GameObject;
|
||||||
|
|
||||||
|
switch (_selectedMode)
|
||||||
|
{
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
GUILayout.Label("Path");
|
||||||
|
|
||||||
|
_replacePath = EditorGUILayout.TextField(_replacePath);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
GUILayout.Label("GameObject");
|
||||||
|
|
||||||
|
_replaceGameObject = (GameObject)EditorGUILayout.ObjectField(_replaceGameObject, typeof(GameObject), true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
EditorGUI.BeginChangeCheck();
|
||||||
|
|
||||||
|
GUILayout.Label("Selected Animation Clip", GUILayout.Width(170));
|
||||||
|
|
||||||
|
switch (_currentSelectionGameObject)
|
||||||
|
{
|
||||||
|
|
||||||
|
case TypeGameObject.GameObject:
|
||||||
|
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
index = EditorGUILayout.Popup(index, _clipNames.ToArray(), GUILayout.Width(300));
|
||||||
|
|
||||||
|
if (index == 0)
|
||||||
|
{
|
||||||
|
_currentAnimationClips = _myanimationClips;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_currentAnimationClips = new List<AnimationClip>() { _myanimationClips[index - 1] };
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case TypeGameObject.None:
|
||||||
|
|
||||||
|
GUI.enabled = false;
|
||||||
|
|
||||||
|
EditorGUILayout.Popup(index, new string[] { "" }, GUILayout.Width(300));
|
||||||
|
|
||||||
|
animations = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorGUI.EndChangeCheck())
|
||||||
|
{
|
||||||
|
FillModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.enabled = _currentSelectionGameObject == TypeGameObject.GameObject;
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
GUILayout.Label("Replacement");
|
||||||
|
|
||||||
|
switch (_selectedMode)
|
||||||
|
{
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
_replacementPath = EditorGUILayout.TextField(_replacementPath);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
_replacementGameObject = (GameObject)EditorGUILayout.ObjectField(_replacementGameObject, typeof(GameObject), true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
if (GUILayout.Button("Replace", GUILayout.Width(205)))
|
||||||
|
{
|
||||||
|
Replace();
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameObjects.Clear();
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
GUILayout.BeginHorizontal("Toolbar");
|
||||||
|
|
||||||
|
GUILayout.Label("Animation Clip", GUILayout.Width(188));
|
||||||
|
|
||||||
|
GUILayout.Label("Property");
|
||||||
|
|
||||||
|
GUILayout.Label("Path");
|
||||||
|
|
||||||
|
GUILayout.Label("Object", GUILayout.Width(150));
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply All", EditorStyles.toolbarButton, GUILayout.Width(70)))
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var pathData in _pathDataList)
|
||||||
|
{
|
||||||
|
UpdatePath(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.FocusTextInControl(null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Revert All", EditorStyles.toolbarButton, GUILayout.Width(70)))
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var pathData in _pathDataList)
|
||||||
|
{
|
||||||
|
Revert(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUI.FocusTextInControl(null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
if (_currentSelectionGameObject != TypeGameObject.None)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_pathDataList != null)
|
||||||
|
{
|
||||||
|
scrollPosContent = EditorGUILayout.BeginScrollView(scrollPosContent);
|
||||||
|
|
||||||
|
foreach (var pathData in _pathDataList)
|
||||||
|
{
|
||||||
|
GUICreatePathItem(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndScrollView();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!animations)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUI.enabled = false;
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField(new GUIContent(EditorGUIUtility.ObjectContent(null, typeof(Animator)).image), GUILayout.Width(16));
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Property");
|
||||||
|
|
||||||
|
EditorGUILayout.TextField("SomeNewObject");
|
||||||
|
|
||||||
|
EditorGUILayout.ObjectField(null, typeof(GameObject), true);
|
||||||
|
|
||||||
|
GUILayout.Button("Apply", GUILayout.Width(60));
|
||||||
|
|
||||||
|
GUILayout.Button("Revert", GUILayout.Width(60));
|
||||||
|
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
EditorGUILayout.HelpBox("Please select a GameObject or Prefab with an Animator, Animation Clip or an Animator Controller.", MessageType.Info);
|
||||||
|
|
||||||
|
GUILayout.FlexibleSpace();
|
||||||
|
|
||||||
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Revert(PathData pathData)
|
||||||
|
{
|
||||||
|
pathData.CurrentPath = pathData.LastPath;
|
||||||
|
|
||||||
|
UpdatePath(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Replace()
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (_selectedMode)
|
||||||
|
{
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_replacePath))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pathData in _pathDataList)
|
||||||
|
{
|
||||||
|
pathData.CurrentPath = pathData.CurrentPath.Replace(_replacePath, _replacementPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
|
||||||
|
if (_replaceGameObject == null || _replacementGameObject == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pathData in _pathDataList)
|
||||||
|
{
|
||||||
|
if (pathData.CurrentPath.Equals(ChildPath(_replaceGameObject)))
|
||||||
|
{
|
||||||
|
pathData.CurrentPath = ChildPath(_replacementGameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
DrawGui();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GUICreatePathItem(PathData pathData)
|
||||||
|
{
|
||||||
|
|
||||||
|
GameObject newObj;
|
||||||
|
|
||||||
|
GameObject obj;
|
||||||
|
|
||||||
|
obj = FindObjectInRoot(pathData.CurrentPath);
|
||||||
|
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
|
||||||
|
GUIStyle propertyNameStyle = new GUIStyle(EditorStyles.label);
|
||||||
|
propertyNameStyle.richText = true;
|
||||||
|
|
||||||
|
GUIStyle pathNameStyle = new GUIStyle(EditorStyles.textField);
|
||||||
|
|
||||||
|
if (obj == null || obj.GetComponent(pathData.EditorCurve.type) == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
propertyNameStyle.normal.textColor = Color.yellow;
|
||||||
|
|
||||||
|
pathNameStyle.normal.textColor = Color.yellow;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField(pathData.ClipName, GUILayout.Width(280));
|
||||||
|
|
||||||
|
GUILayout.Space(-90);
|
||||||
|
|
||||||
|
var lastPath = pathData.CurrentPath.Split('/').Last();
|
||||||
|
var gameObjectName = string.IsNullOrEmpty(lastPath) ? obj?.name : lastPath;
|
||||||
|
EditorGUILayout.LabelField(new GUIContent(EditorGUIUtility.ObjectContent(null, pathData.EditorCurve.type).image), GUILayout.Width(16));
|
||||||
|
EditorGUILayout.LabelField(
|
||||||
|
$"<i>{gameObjectName}</i> - " +
|
||||||
|
$"{string.Join(" ", Regex.Split(pathData.EditorCurve.type.Name, @"(?<!^)(?=[A-Z])"))} - " +
|
||||||
|
$"<b>{ObjectNames.NicifyVariableName(pathData.EditorCurve.propertyName)}</b>",
|
||||||
|
propertyNameStyle
|
||||||
|
);
|
||||||
|
|
||||||
|
GUIStyle buttonStyle = new GUIStyle(EditorStyles.miniButton);
|
||||||
|
|
||||||
|
|
||||||
|
if (!pathData.CurrentPath.Equals(pathData.EditorCurve.path))
|
||||||
|
{
|
||||||
|
|
||||||
|
buttonStyle.fontStyle = FontStyle.Bold;
|
||||||
|
|
||||||
|
pathNameStyle.fontStyle = FontStyle.Bold;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pathData.CurrentPath = EditorGUILayout.TextField(pathData.CurrentPath, pathNameStyle);
|
||||||
|
|
||||||
|
Color standardColor = GUI.color;
|
||||||
|
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
GUI.color = Color.white;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == null || obj.GetComponent(pathData.EditorCurve.type) == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
GUI.color = Color.yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
newObj = (GameObject)EditorGUILayout.ObjectField(obj, typeof(GameObject), true, GUILayout.Width(150));
|
||||||
|
|
||||||
|
if (obj != null)
|
||||||
|
{
|
||||||
|
_gameObjects.Add(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
GUI.color = standardColor;
|
||||||
|
|
||||||
|
GUI.enabled = true;
|
||||||
|
|
||||||
|
buttonStyle.fontSize = 11;
|
||||||
|
|
||||||
|
buttonStyle.fixedHeight = 18;
|
||||||
|
|
||||||
|
buttonStyle.fixedWidth = 68;
|
||||||
|
|
||||||
|
if (GUILayout.Button("Apply", buttonStyle) && !pathData.CurrentPath.Equals(pathData.EditorCurve.path))
|
||||||
|
{
|
||||||
|
|
||||||
|
UpdatePath(pathData);
|
||||||
|
|
||||||
|
EditorGUI.FocusTextInControl(null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
buttonStyle.fontStyle = !pathData.LastPath.Equals(pathData.EditorCurve.path) ? FontStyle.Bold : FontStyle.Normal;
|
||||||
|
|
||||||
|
if (GUILayout.Button("Revert", buttonStyle) && pathData.CurrentPath.Equals(pathData.EditorCurve.path))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
Revert(pathData);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
if (obj != newObj)
|
||||||
|
{
|
||||||
|
|
||||||
|
pathData.CurrentPath = ChildPath(newObj);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (UnityException ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
Debug.LogError(ex.Message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInspectorUpdate()
|
||||||
|
{
|
||||||
|
|
||||||
|
this.Repaint();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FillModel()
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_pathDataList = new List<PathData>();
|
||||||
|
|
||||||
|
foreach (var currentAnimationClip in _currentAnimationClips)
|
||||||
|
{
|
||||||
|
var pathDataListByClip = FillModelWithCurves(currentAnimationClip.name, AnimationUtility.GetCurveBindings(currentAnimationClip), currentAnimationClip);
|
||||||
|
|
||||||
|
var pathDataListByObjectReference = FillModelWithCurves(currentAnimationClip.name, AnimationUtility.GetObjectReferenceCurveBindings(currentAnimationClip), currentAnimationClip);
|
||||||
|
|
||||||
|
_pathDataList.AddRange(pathDataListByClip);
|
||||||
|
|
||||||
|
_pathDataList.AddRange(pathDataListByObjectReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Console.WriteLine(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private List<PathData> FillModelWithCurves(string clipName, EditorCurveBinding[] curves,AnimationClip clip)
|
||||||
|
{
|
||||||
|
var pathDataList = new List<PathData>();
|
||||||
|
|
||||||
|
foreach (var curve in curves)
|
||||||
|
{
|
||||||
|
var pathData = _pathDataList?.Find(pd => pd.EditorCurve.Equals(curve) && pd.ClipName == clipName);
|
||||||
|
|
||||||
|
if (pathData != null)
|
||||||
|
{
|
||||||
|
pathData.EditorCurve = curve;
|
||||||
|
pathDataList.Add(pathData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pathDataList.Add(new PathData(clipName, curve.path, curve.path, curve, clip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathDataList;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePath(PathData pathData)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (pathData.CurrentPath.Equals(pathData.EditorCurve.path))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pathData.LastPath = pathData.EditorCurve.path;
|
||||||
|
|
||||||
|
AssetDatabase.StartAssetEditing();
|
||||||
|
|
||||||
|
AnimationClip animationClip = pathData.Clip;
|
||||||
|
|
||||||
|
Undo.RecordObject(animationClip, "Animation Hierarchy Change");
|
||||||
|
|
||||||
|
AnimationCurve curve = AnimationUtility.GetEditorCurve(animationClip, pathData.EditorCurve);
|
||||||
|
|
||||||
|
ObjectReferenceKeyframe[] objectReferenceCurve = AnimationUtility.GetObjectReferenceCurve(animationClip, pathData.EditorCurve);
|
||||||
|
|
||||||
|
if (curve != null)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(animationClip, pathData.EditorCurve, null);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AnimationUtility.SetObjectReferenceCurve(animationClip, pathData.EditorCurve, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
pathData.EditorCurve.path = pathData.CurrentPath;
|
||||||
|
|
||||||
|
if (curve != null)
|
||||||
|
{
|
||||||
|
AnimationUtility.SetEditorCurve(animationClip, pathData.EditorCurve, curve);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AnimationUtility.SetObjectReferenceCurve(animationClip, pathData.EditorCurve, objectReferenceCurve);
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetDatabase.StopAssetEditing();
|
||||||
|
|
||||||
|
EditorUtility.ClearProgressBar();
|
||||||
|
|
||||||
|
FillModel();
|
||||||
|
|
||||||
|
this.Repaint();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private GameObject FindObjectInRoot(string path)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_animatorObject == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Transform child = _animatorObject.transform.Find(path);
|
||||||
|
|
||||||
|
if (child != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
return child.gameObject;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ChildPath(GameObject obj, bool sep = false)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (_animatorObject == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw new UnityException("Please assign Referenced Animator (Root) first!");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj == _animatorObject.gameObject)
|
||||||
|
{
|
||||||
|
|
||||||
|
return "";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if (obj.transform.parent == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
throw new UnityException("Object must belong to " + _animatorObject.ToString() + "!");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
return ChildPath(obj.transform.parent.gameObject, true) + obj.name + (sep ? "/" : "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Utility Methods
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Utility Events
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,12 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8be52d198504f814db7f9d88b54c5a44
|
||||||
|
timeCreated: 1510337152
|
||||||
|
licenseType: Store
|
||||||
|
MonoImporter:
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Reference in New Issue
Block a user