前陣子因為專案需要,在國外論壇中找到了一個 Animation 動畫反轉腳本,非常好用。雖然中間使用了過時的 AnimationUtility.GetAllCurves,但就功能性來說不是問題。頂多注意一下新版 Unity 能否還支援。
只不過事後已經找不到這個腳本的來源了,如果有翻到的話會再標出來。
腳本匯入與使用方法
- 在 Assets 目錄下新增一個名為 Editor 的資料夾。
- 在 Editor 中新增一個 ReverseAnimationContext.cs 腳本。
- 將本文提供的程式碼全部覆寫至 ReverseAnimationContext.cs 腳本中。
- 在欲反轉的 Animation Clip 上按下 滑鼠右鍵 -> Create -> Create Reversed Clip。
- 反轉完成的 Animation Clip 將會命名為 [原動畫名稱]_Reversed。
ReverseAnimationContext 腳本原始碼
using UnityEditor; using UnityEngine; using System.IO; public static class ReverseAnimationContext { [MenuItem("Assets/Create/Create Reversed Clip", false, 14)] private static void ReverseClip() { 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 = directoryPath + Path.DirectorySeparatorChar + fileName + "_Reversed" + fileExtension; var clip = GetSelectedClip(); AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(Selection.activeObject), copiedFilePath); clip = (AnimationClip)AssetDatabase.LoadAssetAtPath(copiedFilePath, typeof(AnimationClip)); if (clip == null) return; float clipLength = clip.length; var curves = AnimationUtility.GetAllCurves(clip, true); clip.ClearCurves(); foreach (AnimationClipCurveData curve in curves) { var keys = curve.curve.keys; int keyCount = keys.Length; var postWrapmode = curve.curve.postWrapMode; curve.curve.postWrapMode = curve.curve.preWrapMode; curve.curve.preWrapMode = postWrapmode; for (int i = 0; i < keyCount; i++) { Keyframe K = keys[i]; K.time = clipLength - K.time; var tmp = -K.inTangent; K.inTangent = -K.outTangent; K.outTangent = tmp; keys[i] = K; } curve.curve.keys = keys; clip.SetCurve(curve.path, curve.type, curve.propertyName, curve.curve); } var events = AnimationUtility.GetAnimationEvents(clip); if (events.Length > 0) { for (int i = 0; i < events.Length; i++) { events[i].time = clipLength - events[i].time; } AnimationUtility.SetAnimationEvents(clip, events); } Debug.Log("Animation reversed!"); } [MenuItem("Assets/Create Reversed Clip", true)] static bool ReverseClipValidation() { return Selection.activeObject.GetType() == typeof(AnimationClip); } public static AnimationClip GetSelectedClip() { var clips = Selection.GetFiltered(typeof(AnimationClip), SelectionMode.Assets); if (clips.Length > 0) { return clips[0] as AnimationClip; } return null; } }