using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif using System.Collections.Generic; using System; using System.IO; namespace Thousandto.Cinematic { //剧情对象 [Serializable] public class CinematicObj : ICinematic { public int EventType = 0; public List KeyframeList; public string Name; public int CurFrame = -1; //帧率 public int FrameRate = 30; public bool IsCamera; public int CameraDepth = 10; public int LayMask = 1; public bool IsFollowCamera = false; [NonSerialized] public Vector3[] PathV3Array; [NonSerialized] public GameObject GameObject; [NonSerialized] public Animation Animation; [NonSerialized] public Action RefreshAction; //是否场景里面的物件,这种物件是不能销毁的 [NonSerialized] private bool _isSceneObj = false; //当前是camera,只有等到第一个有事件的帧才能显现出来 [NonSerialized] private bool _isCameraCanShow = true; //包含位移的关键帧 [NonSerialized] public List TransKeyframeList; //关键帧图片宽度 private int _keyFrameIconWidth = 15; [NonSerialized] public Dictionary KeyframeDict; public override void WriteAll(BinaryWriter bw) { //写入顺序必须按照上面成员定义的顺序,读取亦然 PrepareWriter(bw); WriteInt(EventType); WriteList(KeyframeList); WriteString(Name); WriteInt(CurFrame); WriteInt(FrameRate); WriteBool(IsCamera); WriteInt(CameraDepth); WriteInt(LayMask); WriteV3Array(PathV3Array); } public override void ReadAll(BinaryReader rd) { PrepareReader(rd); EventType = ReadInt(); KeyframeList = ReadList(); Name = ReadString(); CurFrame =ReadInt(); FrameRate = ReadInt(); IsCamera = ReadBool(); CameraDepth = ReadInt(); if (CameraDepth < 10) CameraDepth = 10; LayMask = ReadInt(); PathV3Array = ReadV3Array(); } public CinematicObj() { KeyframeList = new List(); TransKeyframeList = new List(); Name = GetType().Name; } public CinematicObj(string name) { KeyframeList = new List(); TransKeyframeList = new List(); Name = name; InitGameObject(); } //保存之前,调用一次这个函数 public void SortKeyframe() { KeyframeList.Sort((a, b) => { return a.Keyframe - b.Keyframe; }); KeyframeDict = new Dictionary(); for (int i = 0; i < KeyframeList.Count; ++i) { if (i - 1 >= 0) KeyframeList[i].PreEventData = KeyframeList[i - 1]; else KeyframeList[i].PreEventData = null; if (i + 1 < KeyframeList.Count) KeyframeList[i].NextKeyframe = KeyframeList[i + 1]; else KeyframeList[i].NextKeyframe = null; KeyframeDict.Add(KeyframeList[i].Keyframe, KeyframeList[i]); KeyframeList[i].RemoveTransEventWhileHasSyncEvent(); //runtime 使用 for(int m = 0; m < KeyframeList[i].EventData.Count; ++m) { if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.坐标变换) { KeyframeList[i].TransformEvent = KeyframeList[i].EventData[m]; TransKeyframeList.Add(KeyframeList[i]); } if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.同步到本地相机坐标 || KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.同步到本地角色坐标) { KeyframeList[i].HasSyncTrans = true; } if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.播放动作) { KeyframeList[i].AnimEvent = KeyframeList[i].EventData[m]; } } } //给当前帧赋值下一个含有位移的关键帧 for (int n = 1; n < KeyframeList.Count; ++n) { var curKeyframe = KeyframeList[n - 1]; curKeyframe.NextTransKeyframe = null; var nextKeyframe = KeyframeList[n]; while (nextKeyframe != null) { if (nextKeyframe.TransformEvent != null) { curKeyframe.NextTransKeyframe = nextKeyframe; break; } nextKeyframe = nextKeyframe.NextKeyframe; } } } public CinematicKeyframe GetKeyframeData(int frame) { InitDicData(); CinematicKeyframe ret = null; KeyframeDict.TryGetValue(frame, out ret); return ret; } private void InitDicData() { if(KeyframeDict == null) { KeyframeDict = new Dictionary(); for (int i = 0; i < KeyframeList.Count; ++i) { if (i - 1 >= 0) KeyframeList[i].PreEventData = KeyframeList[i - 1]; else KeyframeList[i].PreEventData = null; if (i + 1 < KeyframeList.Count) KeyframeList[i].NextKeyframe = KeyframeList[i + 1]; else KeyframeList[i].NextKeyframe = null; KeyframeDict.Add(KeyframeList[i].Keyframe, KeyframeList[i]); } } } public CinematicKeyframe GetPreTransKeyframeData(int frame) { CinematicKeyframe ret = null; for(int i = KeyframeList.Count - 1; i >= 0; --i) { if(KeyframeList[i].Keyframe < frame && KeyframeList[i].GetTransEvent() != null) { ret = KeyframeList[i]; break; } } return ret; } public CinematicKeyframe GetPreAnimKeyframeData(int frame) { CinematicKeyframe ret = null; for (int i = KeyframeList.Count - 1; i >= 0; --i) { if (KeyframeList[i].Keyframe < frame && KeyframeList[i].GetAnimEvent() != null) { ret = KeyframeList[i]; break; } } return ret; } public bool ExistFrame(int frame, out CinematicKeyframe keyFrameData) { keyFrameData = null; for (int i = 0; i < KeyframeList.Count; ++i) { if (KeyframeList[i].Keyframe == frame) { keyFrameData = KeyframeList[i]; return true; } } return false; } public bool ExistFrame(int frame) { for (int i = 0; i < KeyframeList.Count; ++i) { if (KeyframeList[i].Keyframe == frame) { return true; } } return false; } public void AddEvent(int frame, KeyFrameEvent e) { CinematicKeyframe eData; if(ExistFrame(frame, out eData)) { eData.AddEvent(new CinematicEventData(e)); } } public bool IsEndFrame(int frame) { if (KeyframeList == null || KeyframeList.Count == 0) return true; return KeyframeList[KeyframeList.Count - 1].Keyframe <= frame; } //添加关键帧 public CinematicKeyframe AddFrame(int frame) { CinematicKeyframe keyFrameData; if (ExistFrame(frame, out keyFrameData)) { keyFrameData.SetData(frame); } else { keyFrameData = new CinematicKeyframe(); keyFrameData.SetData(frame); KeyframeList.Add(keyFrameData); } keyFrameData.Selected = true; CurFrame = frame; return keyFrameData; } //移除关键帧 public void RemoveFrame(int frame) { CinematicKeyframe keyFrameData = null; if (ExistFrame(frame, out keyFrameData)) { KeyframeList.Remove(keyFrameData); keyFrameData.OnRefreshEditor(true); } } //复制关键帧 public List CopyFrameData(int frame) { CinematicKeyframe keyFrameData; List retList = new List(); if (!ExistFrame(frame, out keyFrameData)) return retList; retList = keyFrameData.CloneEventData(); return retList; } //粘贴关键帧 public void PasteFrameData(int frame, List eData) { CinematicKeyframe keyFrameData; if (ExistFrame(frame, out keyFrameData)) { keyFrameData.SetData(frame, eData); } else { keyFrameData = new CinematicKeyframe(); keyFrameData.SetData(frame, eData); KeyframeList.Add(keyFrameData); } keyFrameData.Selected = true; CurFrame = frame; } public void ClearSelectState() { for(int i = 0; i < KeyframeList.Count; ++i) { KeyframeList[i].Selected = false; } } public void SetSelectState(int frame) { CinematicKeyframe keyFrameData; if(ExistFrame(frame, out keyFrameData)) { keyFrameData.SetSelected(); } } public void MoveFrameWhileDrag(int deltaFrame) { for(int i = 0; i < KeyframeList.Count; ++i) { if(KeyframeList[i].Selected) { KeyframeList[i].Keyframe += deltaFrame; if(KeyframeList[i].Keyframe < 0) { KeyframeList[i].Keyframe = 0; } KeyframeList[i].OnRefreshEditor(); } } ResetTransState(); SortKeyframe(); RefreshEditorData(); } public void RefreshEditorData() { if (RefreshAction != null) RefreshAction(); } static Vector3 CalculateLinearVector(Vector3 start, Vector3 end, float t, float t2) { float distance = (end - start).magnitude; Vector3 deltaV3 = end - start; Vector3 dir = (end - start).normalized; Vector3 newStart = start + (dir * distance / (t)) * t2; return newStart; } static Quaternion CalculateLinearQuaternion(Quaternion from, Quaternion to, float t, float t2) { return Quaternion.Slerp(from, to, (1f / (t)) * t2); } #region runtime [NonSerialized] private bool _hasNextTransform = true; [NonSerialized] private CinematicEventData _nextTransEvent; [NonSerialized] private List _childrenGO; public void Prepare() { SortKeyframe(); ResetTransState(); InitGameObject(); } public void ResetTransState() { _nextTransEvent = null; _hasNextTransform = true; } public void InitGameObject() { if (GameObject == null) { _childrenGO = new List(); GameObject = new GameObject(Name); GameObject.transform.parent = CinematicManager.RootGo.transform; if(IsCamera) { GameObject.name = "Camera"; var camera = GameObject.AddComponent(); camera.depth = CameraDepth; camera.cullingMask = LayMask; GameObject.SetActive(false); _isCameraCanShow = false; } #if UNITY_EDITOR //编辑器下描绘曲线 var script = GameObject.AddComponent(); script.CinematicObj = this; #endif } } public void SetCameraLayerMask(int layerMask) { LayMask = layerMask; if (GameObject == null) return; Camera camera = GameObject.GetComponent(); if(camera != null) { camera.cullingMask = LayMask; camera.depth = CameraDepth; } } public void ClearChild() { if (_childrenGO == null) return; for(int i = 0; i < _childrenGO.Count; ++i) { #if UNITY_EDITOR GameObject.DestroyImmediate(_childrenGO[i]); #else GameObject.Destroy(_childrenGO[i]); #endif } _childrenGO.Clear(); } public void Destory() { if (GameObject != null && !_isSceneObj) { #if UNITY_EDITOR GameObject.DestroyImmediate(GameObject); #else GameObject.Destroy(GameObject); #endif } if(_childrenGO != null) _childrenGO.Clear(); } public void LoadPrefab(string param, string editorParam, bool isLocalPlayer = false) { _isSceneObj = false; ClearChild(); { UnityEngine.Debug.LogWarning("Use editor load prefab!!!"); //if (CinematicObjManager.IsEditorPreview && !string.IsNullOrEmpty(editorParam)) { GameObject go = GameObject.Instantiate(Resources.Load(editorParam)) as GameObject; go.transform.parent = GameObject.transform; go.transform.localPosition = Vector3.zero; go.transform.localScale = Vector3.one; go.transform.localRotation = Quaternion.identity; _childrenGO.Add(go); Animation = go.GetComponent(); //return; } } } public void LoadPrefabFromScene(string nodeFullPath) { //不做clear,可能会删除掉场景中的物件 //ClearChild(); _isSceneObj = true; GameObject = GameObject.Find(nodeFullPath); Animation = GameObject.GetComponent(); } public void SetTransform(CinematicEventData data) { if (GameObject == null) return; SetCameraVisiable(); GameObject.transform.localPosition = data.Position; GameObject.transform.localScale = data.Scale; GameObject.transform.localRotation = Quaternion.Euler(data.Rotation); } public void SetCameraVisiable() { if (IsCamera && !_isCameraCanShow) { GameObject.SetActive(true); _isCameraCanShow = true; } } //曲线变换 public void SetTransformCurveTo(CinematicEventData preTransData, CinematicKeyframe curKeyframe, float preKeyframe, float deltaFrame) { if (IsCamera && !_isCameraCanShow) { GameObject.SetActive(true); _isCameraCanShow = true; } var nextKeyframe = deltaFrame > 0 ? curKeyframe.NextTransKeyframe: curKeyframe.PreEventData; if (!_hasNextTransform || nextKeyframe == null || GameObject == null) return; _nextTransEvent = nextKeyframe.TransformEvent; float durationFame = nextKeyframe.Keyframe - preKeyframe; if (durationFame > 0) { if (deltaFrame < 0) deltaFrame = durationFame + deltaFrame; //路点小于2,用线性差值 或者不使用曲线 if (PathV3Array.Length < 2 || !curKeyframe.TransformEvent.UseCurve) { GameObject.transform.localPosition = CalculateLinearVector(preTransData.Position, _nextTransEvent.Position, durationFame, deltaFrame); } else { //去掉曲线影响,相同的两个点还会产生位移的情况 if (curKeyframe.TransformEvent.Position == nextKeyframe.TransformEvent.Position) { GameObject.transform.localPosition = curKeyframe.TransformEvent.Position; curKeyframe.TransPercentageInCurve = nextKeyframe.TransPercentageInCurve; } else { //偏移量/活动区间 = 该区域移动百分比 float percent = (deltaFrame / durationFame) * (nextKeyframe.TransPercentageInCurve - curKeyframe.TransPercentageInCurve) + curKeyframe.TransPercentageInCurve; Vector3 curvPos = CinematicSerialize.Interp(PathV3Array, percent); //Vector3 newDir = (curvPos - GameObject.transform.localPosition); //newDir.y = 0; //GameObject.transform.forward = newDir; GameObject.transform.localPosition = curvPos; } } GameObject.transform.localScale = CalculateLinearVector(preTransData.Scale, _nextTransEvent.Scale, durationFame, deltaFrame); GameObject.transform.localRotation = CalculateLinearQuaternion(Quaternion.Euler(preTransData.Rotation), Quaternion.Euler(_nextTransEvent.Rotation), durationFame, deltaFrame); } } //线性变换 public void SetTransform(CinematicEventData fromTrans, CinematicEventData toTrans, float durationFrame, float deltaFrame) { if (GameObject == null || fromTrans == null || toTrans == null || durationFrame == 0) return; GameObject.transform.localPosition = CalculateLinearVector(fromTrans.Position, toTrans.Position, durationFrame, deltaFrame); GameObject.transform.localScale = CalculateLinearVector(fromTrans.Scale, toTrans.Scale, durationFrame, deltaFrame); GameObject.transform.localRotation = CalculateLinearQuaternion(Quaternion.Euler(fromTrans.Rotation), Quaternion.Euler(toTrans.Rotation), durationFrame, deltaFrame); } //播放动作,支持逐帧播放 public void PlayAnimationByFrame(CinematicEventData eventData, int keyframe, float curFrame) { if (Animation != null && eventData != null && curFrame >= keyframe && eventData.IsLocalPlayer) { var animEvent = eventData; if (Animation[animEvent.Param] != null) { { float durationFame = curFrame - keyframe; AnimationState state = Animation[animEvent.Param]; AnimationClip clip = Animation.GetClip(animEvent.Param); float length = state.length; float totalFrame = length * 30;// clip.frameRate; float deltaTime = (durationFame / totalFrame); float speed = 1; if (!string.IsNullOrEmpty(eventData.EditorParam)) { if (!float.TryParse(eventData.EditorParam, out speed)) speed = 1; } deltaTime *= speed; if (animEvent.WrapMode == WrapMode.Loop) { if (deltaTime > 1.0f) { deltaTime = deltaTime - (float)Math.Truncate(deltaTime); } } state.normalizedTime = deltaTime; state.normalizedSpeed = 0; } Animation.Play(animEvent.Param); } } } //播放动作,不按照帧播放 public void PlayAnimation(CinematicEventData eventData) { if (Animation != null && eventData != null) { var animEvent = eventData; if (Animation[animEvent.Param] != null) { Animation.Stop(); var state = Animation[animEvent.Param]; state.wrapMode = eventData.WrapMode; float speed = 1; if (!string.IsNullOrEmpty(eventData.EditorParam)) { if (!float.TryParse(eventData.EditorParam, out speed)) speed = 1; } state.speed = speed; Animation.Play(animEvent.Param); } } } public void Update() { } public void EditorUpdate() { if (GameObject != null) Name = GameObject.name; } #endregion } }