using System; using System.Collections; using System.Collections.Generic; using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif // 不要修改枚举的顺序,只能在后面新加,不能删除 public enum EAnimationToogle { Combo = 0, // 连击 SuperArmor = 1, //霸体 Break = 2, // 打断 } [Serializable] public struct FromTo { [SerializeField] public float from; [SerializeField] public float to; public Vector2 fromTo { get { return new Vector2(from, to); } set { from = value.x; to = value.y; } } public FromTo(float from, float to) { this.from = from; this.to = to; } public FromTo(Vector2 fromTo) { this.from = fromTo.x; this.to = fromTo.y; } } [Serializable] public class ToggleTimeDictionary : SerializableDictionary { } public enum EAnimationCurve { TimeScale = 0, // RootMotionScale = 1, } [Serializable] public class CurveDictionary : SerializableDictionary { } [Serializable] public struct AnimationParameter { [Serializable] public struct Setter { [SerializeField] public float normalizedTime; [SerializeField] public float value; } [SerializeField] public List setters; } public enum EAnimationParameter { Visibility = 0, } [Serializable] public class ParameterDictionary : SerializableDictionary { } [Serializable] public class RootMotionOverrideData { [Serializable] public class PosData { [SerializeField] public Vector3 position; [SerializeField] public int frame; public PosData(int frame, Vector3 pos) { this.frame = frame; this.position = pos; } } [SerializeField] public List positions; public RootMotionOverrideData() { positions = new List(); } public Vector3 GetPosition(float frame) { if (positions == null || positions.Count == 0) return Vector3.zero; positions.Sort((p1, p2) => { if (p1.frame < p2.frame) return -1; if (p1.frame > p2.frame) return 1; return 0; }); int prev = 0; int next = 0; for(int i = 0;i < positions.Count; ++i) { if(positions[i].frame > frame) { break; } prev = i; next = Mathf.Clamp(i + 1, 0, positions.Count - 1); } float t = 0; if(prev != next) { t = (frame - positions[prev].frame) / (positions[next].frame - positions[prev].frame); } Vector3 pos = Vector3.Lerp(positions[prev].position, positions[next].position, t); return pos; } public Vector3 GetRootMotionDistance(float prevFrame, float curFrame) { Vector3 p1 = GetPosition(prevFrame); Vector3 p2 = GetPosition(curFrame); return p2 - p1; } public void SetPosition(int frame, Vector3 position) { if(positions == null) { positions = new List(); } PosData pd = positions.Find(s => s.frame == frame); if(pd != null) { pd.position = position; } else { positions.Add(new PosData(frame, position)); } } public void RemovePositionAtFrame(float frame) { if (positions == null) return; PosData pd = positions.Find(s => s.frame == frame); if(pd != null) { positions.Remove(pd); } } } // 某个动画的数据,包括帧事件、碰撞盒、速度曲线 [CreateAssetMenu(fileName = "Animation Data")] public class AnimationData : ScriptableObject { public string animationName; public string animationPath; public List animationEvents; public List hurtBoxes; public List hitBoxes; public List throwBoxes; public List blockBoxes; public List defendBoxes; public bool overrideRootMotion; public RootMotionOverrideData rootMotionOverrideData; // 对应的进度的播放速度,默认是1 [UnityEngine.Serialization.FormerlySerializedAs("curve")] public AnimationCurve speedCurve; public CurveDictionary curves; public ToggleTimeDictionary toggles; public ParameterDictionary parameters; public const int FPS = 30; public AnimationData() { Keyframe frame0 = new Keyframe(0, 1); Keyframe frame1 = new Keyframe(1, 1); speedCurve = new AnimationCurve(frame0, frame1); } public List GetColliderBoxesByType(ColliderBox.EColliderType type) { switch (type) { case ColliderBox.EColliderType.HurtBox: return hurtBoxes; case ColliderBox.EColliderType.HitBox: return hitBoxes; case ColliderBox.EColliderType.BlockBox: return blockBoxes; case ColliderBox.EColliderType.ThrowBox: return throwBoxes; case ColliderBox.EColliderType.DefendBox: return defendBoxes; } return null; } public bool HasParameter(EAnimationParameter parameterName) { if (!parameters.ContainsKey(parameterName)) return false; return true; } public float GetParameter(EAnimationParameter parameterName, float normalizedTime) { if (!parameters.ContainsKey(parameterName)) return 0; var parameter = parameters[parameterName]; parameter.setters.Sort((AnimationParameter.Setter a, AnimationParameter.Setter b) => { return a.normalizedTime - b.normalizedTime < 0 ? -1 : 1; }); float value = 0; for (int i = 0; i < parameter.setters.Count; ++i) { AnimationParameter.Setter setter = parameter.setters[i]; if (setter.normalizedTime > normalizedTime) break; value = setter.value; } return value; } public bool HasCurve(EAnimationCurve curve) { return curves != null && curves.ContainsKey(curve); } public AnimationCurve GetCurve(EAnimationCurve curve) { if (!HasCurve(curve)) return null; return curves[curve]; } public bool HasToggle(EAnimationToogle toggle) { return toggles != null && toggles.ContainsKey(toggle); } public bool IsToggleOpen(EAnimationToogle toggle, float normalizedTime) { if (!HasToggle(toggle)) { return false; } return toggles[toggle].to >= normalizedTime && normalizedTime >= toggles[toggle].from; } public ColliderInfo GetColliderInfo(ColliderBox.EColliderType type, int index, float playbackTime) { return GetColliderInfoByFrame(type, index, playbackTime * FPS); } public ColliderInfo GetColliderInfoByFrame(ColliderBox.EColliderType type, int index, float frame) { ColliderInfo info = new ColliderInfo(); var colliders = GetColliderBoxesByType(type); if (colliders == null || colliders.Count <= index) return info; //info.isValid == false info = colliders[index].GetColliderInfo(frame); return info; } public ColliderInfo[] GetCollidersInfo(ColliderBox.EColliderType type, float playbackTime) { return GetCollidersInfoByFrame(type, playbackTime * FPS); } public ColliderInfo[] GetCollidersInfoByFrame(ColliderBox.EColliderType type, float frame) { var colliders = GetColliderBoxesByType(type); if (colliders == null || colliders.Count == 0) return null; ColliderInfo[] infos = new ColliderInfo[colliders.Count]; for(int i = 0; i < colliders.Count; ++i) { infos[i] = colliders[i].GetColliderInfo(frame); } return infos; } public ColliderInfo[] GetActiveCollidersInfo(ColliderBox.EColliderType type, float playbackTime) { return GetActiveCollidersInfoByFrame(type , playbackTime * FPS); } public ColliderInfo[] GetActiveCollidersInfoByFrame(ColliderBox.EColliderType type, float frame) { var all = GetCollidersInfoByFrame(type, frame); if (all == null || all.Length == 0) return null; int activeCount = 0; foreach(var c in all) { if (c.active) activeCount++; } if (activeCount == 0) return null; ColliderInfo[] active = new ColliderInfo[activeCount]; int i = 0; foreach(var c in all) { if(c.active) { active[i++] = c; } } return active; } public int GetBoxesCount() { int hurt = hurtBoxes != null ? hurtBoxes.Count : 0; int hit = hitBoxes != null ? hitBoxes.Count : 0; int thro = throwBoxes != null ? throwBoxes.Count : 0; int block = blockBoxes != null ? blockBoxes.Count : 0; int defend = defendBoxes != null ? defendBoxes.Count : 0; return hurt + hit + thro + block + defend; } public void AddBox(ref List boxList, ColliderData box) { if (boxList == null) { boxList = new List(); return; } boxList.Add(box); } public void DeleteBox(ColliderData box) { if (hurtBoxes != null) hurtBoxes.Remove(box); if (hitBoxes != null) hitBoxes.Remove(box); if (throwBoxes != null) throwBoxes.Remove(box); if (blockBoxes != null) blockBoxes.Remove(box); if (defendBoxes != null) defendBoxes.Remove(box); } public ColliderData GetColliderByIndex(int index) { if (hurtBoxes != null && hurtBoxes.Count > index) return hurtBoxes[index]; else index -= hurtBoxes.Count; if (hitBoxes != null && hitBoxes.Count > index) return hitBoxes[index]; else index -= hitBoxes.Count; if (throwBoxes != null && throwBoxes.Count > index) return throwBoxes[index]; else index -= throwBoxes.Count; if (blockBoxes != null && blockBoxes.Count > index) return blockBoxes[index]; else index -= blockBoxes.Count; if (defendBoxes != null && defendBoxes.Count > index) return defendBoxes[index]; else index -= defendBoxes.Count; return null; } public void AddEvent(AnimationEventBase animEvent) { if (this.animationEvents == null) this.animationEvents = new List(); animationEvents.Add(animEvent); } public List GetAnimationEventsAtFrame(int frame) { if (animationEvents == null) return null; List events = ListPool.Get(); events.Clear(); foreach (var animeEvent in animationEvents) { if(animeEvent.startFrame == frame) { events.Add(animeEvent); } } return events; } public int GetMaxAnimationEventsCount() { List frames = GetAnimationEventFrameIndices(); if(frames == null) { ListPool.Release(frames); return 0; } int count = 0; for(int i = 0; i < frames.Count; ++i) { List events = GetAnimationEventsAtFrame(frames[i]); if (count < events.Count) { count = events.Count; } ListPool.Release(events); } ListPool.Release(frames); return count; } public List GetAnimationEventFrameIndices() { if (animationEvents == null) return null; List frames = ListPool.Get(); frames.Clear(); foreach (var animeEvent in animationEvents) { if (!frames.Contains(animeEvent.startFrame)) { frames.Add(animeEvent.startFrame); } } return frames; } public void DeleteEvent(AnimationEventBase animEvent) { if(animationEvents.Contains(animEvent)) { animationEvents.Remove(animEvent); } } public void AddRootMotionOverriderData( ) { this.overrideRootMotion = true; this.rootMotionOverrideData = new RootMotionOverrideData(); } public void DeleteRootMotionOverrideData() { this.overrideRootMotion = false; this.rootMotionOverrideData = null; } #if UNITY_EDITOR public void OnSaveToDisk() { foreach(var animEvent in animationEvents) { if(!AssetDatabase.IsSubAsset(animEvent)) { AssetDatabase.AddObjectToAsset(animEvent, this); } } } #endif }