using System; using System.IO; using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; namespace ActionTool { // ActionTool callback delegates public delegate void CallbackHandler(params object[] objs); public static class ActionManager { public enum UnitType { PC, NPC, } public static string s_Controller = "Assets/ActionTool/controller_temp.controller"; static string s_SettingPath = "Assets/ActionTool/ActionTool Settings.asset"; public static string scenePath { get { return "Assets/ActionTool/ActionToolScene.unity"; } } //public static string s_AnimFolder = "Assets/Art/Animations/"; //public static string s_AnimationDataFolder = "Assets/Data/AnimationData/"; //static string s_RootMotionDataFolder = "Assets/Data/RootMotionData/"; public static ActionEditor AnimationWindow; public static ActionPreviewEditor PreviewWindow; public static ActionEventEditor EventEditWindow; public static ActionColliderFrameEditor ColliderFrameWindow; public static ActionColliderEditor ColliderWindow; public static ActionRootMotionEditor RootMotionEditor; public static ActionToolSettings Settings; //规定timeline上事件的采样频率是30帧 public const int FPS = 30; public static float Speed = 1; public static GameObject CurrentUnit { get { return s_CurrentUnit; } } public static string CurrentAnimationName { get { return s_CurrentAnimationName; } } private static GameObject s_CurrentUnit; private static string s_CurrentAnimationName; public static GameObject unitInstance { get { return s_UnitInstance; } } public static GameObject unitRoot { get; private set; } private static GameObject s_UnitInstance; private static Animator s_Animator; private static AnimatorOverrideController s_OverrideContorller; private static ActionData s_CurActionData; public static ActionData actionData { get { return s_CurActionData; } } public static Vector3 s_InitPosition = Vector3.zero; public static Quaternion s_InitRotation = Quaternion.identity; private static RootMotionData s_RootMotion; private static AnimationData m_SharedAnimationData; // 资源 public static AnimationData sharedAnimationData { get { return m_SharedAnimationData; } } private static AnimationData m_AnimationData; public static AnimationData animationData { get { return m_AnimationData; } set { m_AnimationData = value; if (gizmos) { gizmos.SetAnimationData(value); } } } public static AnimationClip curClip; public static string AnimationDataPath { get { return AssetDatabase.GetAssetPath(sharedAnimationData); } } private static AnimationEventBase m_CurAnimationEvent; public static AnimationEventBase animationEvent { get { return m_CurAnimationEvent; } } private static ColliderData s_CurColliderData; public static ColliderData colliderData { get { return s_CurColliderData; } set { s_CurColliderData = value; } } public static ColliderData.ColliderFrame s_CurEditColliderFrame; public static ColliderData.ColliderFrame editColliderFrame { get { return s_CurEditColliderFrame; } } public static ColliderData s_CurEditFrameCollider; private static ActionToolGizmos s_Gizmos; public static ActionToolGizmos gizmos { get { return s_Gizmos; } } // 是否在自动播放 private static bool s_IsPlay; public static bool IsPlay { get { return s_IsPlay; } } private static GameObject s_RootActionTool; private const string kRootActionTool = "RootActionTool"; private const string kUnitRoot = "UnitRoot"; private static AnimationEventBase copiedAnimationEvent; public static int MaxEventsPerFrame // 所有帧里面事件最多有几个 { get { if (animationData == null) return 0; return animationData.GetMaxAnimationEventsCount(); } } public static int GridRowCount { get { bool hasRM = animationData != null && animationData.overrideRootMotion == true; return (MaxEventsPerFrame + 1) + (animationData != null ? animationData.GetBoxesCount() : 0) + (hasRM ? 1 : 0); } } public static string unitFolder; public static string unitAnimationDataFolder { get { return unitFolder + "AnimationData/"; } } public static string unitRootMotionFolder { get { return unitFolder + "RootMotion/"; } } public static string unitAnimationClipFolder { get { return unitFolder + "AnimationClip/"; } } public static string unitDataFolder { get { return unitFolder + "UnitData/"; } } public static int colliderIndex; public static CallbackHandler onSelectObj; public static void OnSelectObj(GameObject obj) { Release(); s_CurrentUnit = obj; if(s_CurrentUnit != null) { string path = AssetDatabase.GetAssetPath(obj); string folder = Path.GetDirectoryName(path).Replace('\\', '/'); folder = folder.Substring(0, folder.LastIndexOf('/')); unitFolder = folder + "/"; s_UnitInstance = GameObject.Instantiate(obj); InitializeUnitInstance(s_UnitInstance); } onSelectObj?.Invoke(obj); } public static void OnSelectAnimation(string animation) { s_CurrentAnimationName = animation; if (PreviewWindow == null) PreviewWindow = EditorWindow.GetWindow(); PreviewWindow.Repaint(); string animpath = unitAnimationClipFolder + animation + ".anim"; AnimationClip clip = AssetDatabase.LoadAssetAtPath(animpath, typeof(AnimationClip)) as AnimationClip; curClip = clip; if (clip) { s_OverrideContorller["EmptyAction"] = clip; } string rootmotionData = unitRootMotionFolder + animation + ".asset"; s_RootMotion = AssetDatabase.LoadAssetAtPath(rootmotionData); if (s_RootMotion == null) { Debug.LogError("[ActionTool] 没有对应的rootmotion, " + rootmotionData); } if (s_CurActionData == null) s_CurActionData = new ActionData(); s_CurActionData.Initialize(s_Animator, clip, s_RootMotion); string animationDataPath = unitAnimationDataFolder + animation + ".asset"; AnimationData asset = AssetDatabase.LoadAssetAtPath(animationDataPath); m_SharedAnimationData = asset; if(asset != null) animationData = UnityEngine.Object.Instantiate(asset); else animationData = null; OnSelectAnimationEvent(null); OnSelectColliderFrame(null, null); OnSelectBox(null); if (EventEditWindow) EventEditWindow.Close(); if (ColliderFrameWindow) ColliderFrameWindow.Close(); } public static bool HasSelectObj() { return s_CurrentUnit != null; } public static void Release() { if(s_UnitInstance != null) GameObject.DestroyImmediate(s_UnitInstance); s_UnitInstance = null; s_CurrentUnit = null; s_CurrentAnimationName = null; s_Animator = null; s_RootActionTool = GameObject.Find(kRootActionTool); if (s_RootActionTool) GameObject.DestroyImmediate(s_RootActionTool); s_CurActionData = null; s_CurEditColliderFrame = null; s_CurColliderData = null; s_CurrentAnimationName = null; } private static void InitializeUnitInstance(GameObject unit) { if (unit == null) return; unit.transform.position = Vector3.zero; unit.transform.rotation = Quaternion.Euler(0, 90, 0); var tempUnitRoot = GameObject.Find(kUnitRoot); if (tempUnitRoot) GameObject.DestroyImmediate(tempUnitRoot); unitRoot = new GameObject(kUnitRoot); unitRoot.transform.localScale = Vector3.one; unitRoot.transform.rotation = s_InitRotation; unitRoot.transform.position = s_InitPosition; unit.transform.SetParent(unitRoot.transform); s_RootActionTool = GameObject.Find(kRootActionTool); if(s_RootActionTool == null) s_RootActionTool = new GameObject(kRootActionTool); unitRoot.transform.SetParent(s_RootActionTool.transform); s_Animator = unit.GetComponentInChildren(); if(s_Animator == null) { Debug.LogError("[ActionTool] 角色prefab下没有animator"); return; } RuntimeAnimatorController controller = AssetDatabase.LoadAssetAtPath(s_Controller, typeof(RuntimeAnimatorController)) as RuntimeAnimatorController; if(controller == null) { Debug.LogError("[ActionTool] 文件丢失" + s_Controller); return; } s_OverrideContorller = new AnimatorOverrideController(controller); s_OverrideContorller.name = "override controller"; s_Animator.runtimeAnimatorController = s_OverrideContorller; s_Animator.applyRootMotion = false; s_Gizmos = s_RootActionTool.AddComponent(); s_Gizmos.Initialize(unitRoot); Settings = AssetDatabase.LoadAssetAtPath(s_SettingPath); } public static void UpdateFrame() { if (s_CurActionData != null) s_CurActionData.UpdateFrame(); } public static void Pause() { s_IsPlay = !s_IsPlay; if(s_IsPlay && s_CurActionData != null) { s_CurActionData.StartFrame(); } } public static void Start() { if (s_CurActionData != null) s_CurActionData.curAnimTimeNormal = 0; } public static void Stop() { if (s_CurActionData != null) { if (s_IsPlay) Pause(); s_CurActionData.curAnimTimeNormal = 0; } } public static void Previous() { if (s_IsPlay) Pause(); float cur = s_CurActionData.curAnimFrame; float pre = Mathf.Ceil(cur - 1); pre = (int)Mathf.Clamp(pre, 0, s_CurActionData.totalFrame); s_CurActionData.SetCurrentAnimTime(pre); } public static void Next() { if (s_IsPlay) Pause(); float cur = s_CurActionData.curAnimFrame; float next = Mathf.Floor(cur + 1); next = (int)Mathf.Clamp(next, 0, s_CurActionData.totalFrame); s_CurActionData.SetCurrentAnimTime(next); } public static void End() { if (s_CurActionData != null) s_CurActionData.curAnimTimeNormal = 1; } public static void CreateAnimationData() { string animation = s_CurrentAnimationName; string animationDataPath = unitAnimationDataFolder + animation + ".asset"; string animpath = unitAnimationClipFolder + animation + ".anim"; AnimationData animData = new AnimationData(); animData.animationName = s_CurrentAnimationName; animData.animationPath = animpath; AssetDatabase.CreateAsset(animData, animationDataPath); AssetDatabase.Refresh(); m_SharedAnimationData = animData; animationData = UnityEngine.Object.Instantiate(animData); } public static void SaveAnimationData() { if (animationData == null) { Debug.LogError("[ActionTool] 没有animation data数据"); return; } string animation = s_CurrentAnimationName; string animationDataPath = unitAnimationClipFolder + animation + ".asset"; EditorUtility.CopySerialized(animationData, m_SharedAnimationData); m_SharedAnimationData.OnSaveToDisk(); EditorUtility.SetDirty(m_SharedAnimationData); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } public static void NewHurtBox() { if (animationData == null) { Debug.LogError("[ActionTool] 没有animation data数据"); return; } ColliderData box = new ColliderData(ColliderBox.EColliderType.HurtBox, ColliderBox.Pivot.MiddleBottom); animationData.AddBox(ref animationData.hurtBoxes, box); } public static void NewHitBox() { if (animationData == null) { Debug.LogError("[ActionTool] 没有animation data数据"); return; } ColliderData box = new ColliderData(ColliderBox.EColliderType.HitBox, ColliderBox.Pivot.MiddleCenter); animationData.AddBox(ref animationData.hitBoxes, box); } public static void DeleteCurBox() { if(animationData != null && s_CurColliderData != null) { animationData.DeleteBox(s_CurColliderData); s_CurColliderData = null; } } public static void EditCollider() { if (s_CurColliderData == null) return; if(ColliderWindow == null) ColliderWindow = EditorWindow.GetWindow(true); } public static void OnSelectBox(ColliderData collider, int index = 0) { s_CurColliderData = collider; if (ColliderWindow != null) ColliderWindow.Repaint(); colliderIndex = index; EditCollider(); } public static void AddNewBoxFrame(object param) { BoxParam frame = (BoxParam)param; int frameIndex = frame.frame; var data = frame.collider; if(data != null) { var frameData = data.AddFrame(frameIndex); OnSelectColliderFrame(frameData, data); } } public static void DeleteBoxFrame(object param) { BoxParam frame = (BoxParam)param; int frameIndex = frame.frame; var data = frame.collider; if (data != null) { data.DeleteFrame(frameIndex); } } public static void DeleteCurFrame() { if (s_CurEditFrameCollider == null) return; if (s_CurEditColliderFrame == null) return; s_CurEditFrameCollider.DeleteFrame(s_CurEditColliderFrame.frame); s_CurEditColliderFrame = null; } public static void OnSelectColliderFrame(ColliderData.ColliderFrame frame, ColliderData collider = null) { s_CurEditColliderFrame = frame; s_CurEditFrameCollider = collider; if (frame != null) { ColliderFrameWindow = EditorWindow.GetWindow(true); ActionData action = ActionManager.actionData; float normaltime = frame.frame / action.totalFrame; action.curAnimTimeNormal = normaltime; } } public static void AddNewEvent(object param) { EventParam eventParam = (EventParam )param; string eventName = eventParam.eventName; // TimelineEventProxy.EEventType int frame = eventParam.frame; Debug.Log("[ActionTool] Add new event " + eventName); if (animationData == null) { Debug.LogError("[ActionTool] 没有animation data数据"); return; } Type type = TimelineEventProxy.GetTypeByName(eventName); if(type == null) { Debug.LogError("[ActionTool] 没有创建对应的类, " + eventName); return; } AnimationEventBase animEvent = Activator.CreateInstance(type) as AnimationEventBase; if(animEvent) { animEvent.name = animEvent.type.ToString(); animEvent.startFrame = frame; animationData.AddEvent(animEvent); OnSelectAnimationEvent(animEvent); } else { Debug.LogError("[ActionTool] 实例化失败, " + eventName); return; } } public static void PasteEvent(object param) { if (copiedAnimationEvent == null) return; int frame = (int)param; AnimationEventBase animEvent = UnityEngine.Object.Instantiate(copiedAnimationEvent); if(animEvent != null) { animEvent.name = animEvent.type.ToString(); animEvent.startFrame = frame; animationData.AddEvent(animEvent); OnSelectAnimationEvent(animEvent); } } public static void OnSelectAnimationEvent(AnimationEventBase animEvent) { m_CurAnimationEvent = animEvent; if(animEvent != null) { EventEditWindow = EditorWindow.GetWindow(true); } } public static void DeleteEvent(AnimationEventBase animEvent) { if (animationData == null) return; animationData.DeleteEvent(animEvent); } public static void EditRootMotionOverrideData() { RootMotionEditor = EditorWindow.GetWindow(true); } public static void CopyAnimationEvent(AnimationEventBase animEvent) { copiedAnimationEvent = UnityEngine.Object.Instantiate(animEvent); } public static void ResetUnitRootPosAndRot() { unitRoot.transform.position = s_InitPosition; unitRoot.transform.rotation = s_InitRotation; } } }