summaryrefslogtreecommitdiff
path: root/Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-07-07 22:13:48 +0800
committerchai <chaifix@163.com>2021-07-07 22:13:48 +0800
commit3db514468fac20693a257179d35592d0b78e2936 (patch)
treeef0f63324299a1121a76bbe470140b461666303e /Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs
parenta13f10139d33264fc9ebc5a15c75faf16fc7757e (diff)
+RootMotion
Diffstat (limited to 'Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs')
-rw-r--r--Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs247
1 files changed, 246 insertions, 1 deletions
diff --git a/Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs b/Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs
index facf295b..3c8c55a9 100644
--- a/Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs
+++ b/Assets/Scripts/Unit/RootMotion/Editor/RootMotionEditor.cs
@@ -1,12 +1,40 @@
-using System.Collections;
+using System;
+using System.IO;
+using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class RootMotionEditor : EditorWindow
{
+ static string s_AnimFolder = "Assets/Art/Animations/";
+ static string s_Controller = "Assets/Scripts/Unit/RootMotion/controller_rootmotion.controller";
+ static string s_RootMotionDataFolder = "Assets/Data/RootMotionData/";
+
+ GameObject m_Prefab;
+ string m_PrefabName { get { return m_Prefab.name; } }
+ GameObject m_Unit;
+ Transform m_Transform { get { return m_Unit.transform; } }
+ string m_SearchText = "";
+ HashSet<string> m_SelectAnimations;
+ List<string> m_AnimList = new List<string>();
+
+ Animator m_Animator;
+ AnimatorOverrideController m_OverrideController;
+
+ const string kEmptyClipName = "Empty";
+ const string kStateName = "Action";
+
+ [MenuItem("Custom/RootMotion/Create")]
+ static void OpenTool()
+ {
+ RootMotionEditor editor = GetWindow<RootMotionEditor>();
+ }
+
private void OnEnable()
{
+ titleContent = new GUIContent("RootMotion Editor");
+ m_SelectAnimations = new HashSet<string>();
}
private void OnDisable()
@@ -14,4 +42,221 @@ public class RootMotionEditor : EditorWindow
}
+ private void OnGUI()
+ {
+ if (m_SelectAnimations == null) m_SelectAnimations = new HashSet<string>();
+ if(m_AnimList == null)
+ {
+ m_AnimList = new List<string>();
+ if (m_Prefab != null)
+ CollectAnimations(m_Prefab.name);
+ }
+
+ EditorGUILayout.LabelField("Select Unit:");
+ GameObject prefab = EditorGUILayout.ObjectField(m_Prefab, typeof(GameObject), false) as GameObject;
+ if(prefab != m_Prefab)
+ {
+ OnSelectPrefab(prefab);
+ }
+ if(m_Prefab == null)
+ {
+ EditorGUILayout.HelpBox("选择角色", MessageType.Warning);
+ }
+ GUI_SelectAnimation();
+ GUI_Export();
+ }
+
+ private void OnSelectPrefab(GameObject prefab)
+ {
+ m_Prefab = prefab;
+ if(m_Prefab != null)
+ {
+ m_Unit = PrefabUtility.InstantiatePrefab(m_Prefab) as GameObject;
+ InitializeUnit(m_Unit);
+ m_SelectAnimations.Clear();
+ CollectAnimations(m_Prefab.name);
+ }
+ else
+ {
+ m_SelectAnimations.Clear();
+ m_Unit = null;
+ }
+ }
+
+ void InitializeUnit(GameObject unit)
+ {
+ if (unit == null)
+ return;
+
+ m_Animator = unit.GetComponent<Animator>();
+ m_Animator.applyRootMotion = true;
+
+ RuntimeAnimatorController controller = AssetDatabase.LoadAssetAtPath(s_Controller, typeof(RuntimeAnimatorController)) as RuntimeAnimatorController;
+ if (controller)
+ {
+ m_OverrideController = new AnimatorOverrideController(controller);
+ m_Animator.runtimeAnimatorController = m_OverrideController;
+ }
+ }
+
+ void CollectAnimations(string prefabName)
+ {
+ m_AnimList.Clear();
+ string animFolder = s_AnimFolder + m_Prefab.name + "/";
+ string[] animfiles = Directory.GetFiles(animFolder/*, "*.anim"*/);
+ if (animfiles != null && animfiles.Length > 0)
+ {
+ for (int i = 0; i < animfiles.Length; ++i)
+ {
+ string file = animfiles[i];
+ if (file.Contains(".meta"))
+ continue;
+ string animName = Path.GetFileNameWithoutExtension(file);
+ m_AnimList.Add(animName);
+ }
+ }
+ }
+
+ bool IsAllSelected()
+ {
+ if (m_SelectAnimations == null || m_SelectAnimations.Count == 0)
+ return false;
+ if (m_AnimList == null || m_AnimList.Count == 0)
+ return false;
+ return m_AnimList.Count == m_SelectAnimations.Count;
+ }
+
+ Vector2 m_AnimtionListScroll;
+ private void GUI_SelectAnimation()
+ {
+ if (m_Prefab == null)
+ return;
+ EditorGUILayout.LabelField("Select Animations:");
+ m_SearchText = GUILayout.TextField(m_SearchText, "SearchTextField", GUILayout.Width(position.width - 20)).ToLower();
+
+ bool isAllSelected = IsAllSelected();
+ bool allselcted = GUILayout.Toggle(isAllSelected, "全选");
+ if(allselcted && !isAllSelected)
+ {
+ m_SelectAnimations.Clear();
+ m_AnimList.ForEach(s =>m_SelectAnimations.Add(s));
+ }
+ else if(!allselcted && isAllSelected)
+ {
+ m_SelectAnimations.Clear();
+ }
+
+ if (m_AnimList != null && m_AnimList.Count > 0)
+ {
+ m_AnimtionListScroll = EditorGUILayout.BeginScrollView(m_AnimtionListScroll, GUILayout.Height(400));
+
+ for (int i = 0; i < m_AnimList.Count; ++i)
+ {
+ string file = m_AnimList[i];
+ if (file.Contains(".meta"))
+ continue;
+ string animName = Path.GetFileNameWithoutExtension(file);
+ bool show = m_SearchText == string.Empty || m_SearchText == "" || animName.ToLower().Contains(m_SearchText);
+ if (!show)
+ continue;
+ bool bChecked = m_SelectAnimations.Contains(animName);
+ bool check = GUILayout.Toggle(bChecked, animName, GUILayout.Height(15));
+ if (check && !bChecked)
+ m_SelectAnimations.Add(animName);
+ else if(!check && bChecked)
+ m_SelectAnimations.Remove(animName);
+ }
+
+ EditorGUILayout.EndScrollView();
+ }
+ }
+
+ void GUI_Export()
+ {
+ EditorGUILayout.Space();
+ EditorGUILayout.Space();
+
+ GUI.enabled = m_SelectAnimations != null && m_SelectAnimations.Count > 0;
+ if (GUILayout.Button("Export"))
+ {
+ ExportRootMotions();
+ }
+ GUI.enabled = true;
+ }
+
+ void ExportRootMotions()
+ {
+ if (m_SelectAnimations == null || m_SelectAnimations.Count == 0)
+ return;
+
+ foreach(var animation in m_SelectAnimations)
+ {
+ ExportRootMotion(animation);
+ }
+
+ EditorUtility.DisplayDialog("Export RootMotion", "目录 " + s_RootMotionDataFolder + m_Prefab.name, "OK");
+ }
+
+ void ExportRootMotion(string animation)
+ {
+ string animPath = s_AnimFolder + m_PrefabName + "/" + animation + ".anim";
+ string assetPath = s_RootMotionDataFolder + m_PrefabName + "/" + animation + ".asset";
+ AnimationClip clip = AssetDatabase.LoadAssetAtPath<AnimationClip>(animPath);
+ if(clip == null)
+ {
+ Debug.LogError("[RootMotion Editor] 没有对应的animation, " + animPath);
+ return;
+ }
+ m_OverrideController[kEmptyClipName] = clip;
+
+ m_Transform.position = Vector3.zero;
+ m_Transform.rotation = Quaternion.identity;
+
+ float frameRate = clip.frameRate;
+ float timeLen = clip.length;
+
+ float sampleRate = 30; // rootmotion 采样频率,每秒采样30帧
+ float sampleDuration = 1 / sampleRate;
+
+ RootMotionData rootmotion = new RootMotionData();
+ rootmotion.animationName = animation;
+ rootmotion.animationLength = timeLen;
+ rootmotion.fps = sampleRate;
+
+ rootmotion.positionList = new List<Vector3>();
+ rootmotion.positionList.Add(Vector3.zero);
+
+ const float kDeltaTime = 1 / 100f;
+ float t = 0;
+ float sampleTime = 0;
+
+ while(true)
+ {
+ m_Animator.speed = 1;
+ m_Animator.Play(kStateName, 0, t / timeLen);
+ m_Animator.Update(kDeltaTime);
+ m_Animator.speed = 0;
+
+ //m_Transform.rotation *= m_Animator.deltaRotation;
+ //m_Transform.position += m_Animator.deltaPosition;
+
+ sampleTime += kDeltaTime;
+ if(sampleTime >= sampleDuration)
+ {
+ rootmotion.positionList.Add(m_Transform.position);
+ sampleTime = sampleTime - sampleDuration;
+ }
+
+ if (t == timeLen)
+ break;
+ t += kDeltaTime;
+ if (t > timeLen)
+ t = timeLen;
+ }
+
+ rootmotion.frameCount = rootmotion.positionList.Count;
+
+ AssetDatabase.CreateAsset((RootMotionData)rootmotion, assetPath);
+ }
+
}