Files
Main/Assets/Plugins/Code/Cinematic/CinematicObj.cs

654 lines
22 KiB
C#
Raw Normal View History

2025-01-25 04:38:09 +08:00
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<CinematicKeyframe> 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<CinematicKeyframe> TransKeyframeList;
//关键帧图片宽度
private int _keyFrameIconWidth = 15;
[NonSerialized]
public Dictionary<int, CinematicKeyframe> 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<CinematicKeyframe>();
Name = ReadString();
CurFrame =ReadInt();
FrameRate = ReadInt();
IsCamera = ReadBool();
CameraDepth = ReadInt();
if (CameraDepth < 10)
CameraDepth = 10;
LayMask = ReadInt();
PathV3Array = ReadV3Array();
}
public CinematicObj()
{
KeyframeList = new List<CinematicKeyframe>();
TransKeyframeList = new List<CinematicKeyframe>();
Name = GetType().Name;
}
public CinematicObj(string name)
{
KeyframeList = new List<CinematicKeyframe>();
TransKeyframeList = new List<CinematicKeyframe>();
Name = name;
InitGameObject();
}
//保存之前,调用一次这个函数
public void SortKeyframe()
{
KeyframeList.Sort((a, b) => { return a.Keyframe - b.Keyframe; });
KeyframeDict = new Dictionary<int, CinematicKeyframe>();
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<int, CinematicKeyframe>();
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<CinematicEventData> CopyFrameData(int frame)
{
CinematicKeyframe keyFrameData;
List<CinematicEventData> retList = new List<CinematicEventData>();
if (!ExistFrame(frame, out keyFrameData)) return retList;
retList = keyFrameData.CloneEventData();
return retList;
}
//粘贴关键帧
public void PasteFrameData(int frame, List<CinematicEventData> 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<GameObject> _childrenGO;
public void Prepare()
{
SortKeyframe();
ResetTransState();
InitGameObject();
}
public void ResetTransState()
{
_nextTransEvent = null;
_hasNextTransform = true;
}
public void InitGameObject()
{
if (GameObject == null)
{
_childrenGO = new List<GameObject>();
GameObject = new GameObject(Name);
GameObject.transform.parent = CinematicManager.RootGo.transform;
if(IsCamera)
{
GameObject.name = "Camera";
var camera = GameObject.AddComponent<Camera>();
camera.depth = CameraDepth;
camera.cullingMask = LayMask;
GameObject.SetActive(false);
_isCameraCanShow = false;
}
#if UNITY_EDITOR //编辑器下描绘曲线
var script = GameObject.AddComponent<Plugin.CinematicUI_Curve>();
script.CinematicObj = this;
#endif
}
}
public void SetCameraLayerMask(int layerMask)
{
LayMask = layerMask;
if (GameObject == null) return;
Camera camera = GameObject.GetComponent<Camera>();
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<GameObject>(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<Animation>();
//return;
}
}
}
public void LoadPrefabFromScene(string nodeFullPath)
{
//不做clear可能会删除掉场景中的物件
//ClearChild();
_isSceneObj = true;
GameObject = GameObject.Find(nodeFullPath);
Animation = GameObject.GetComponent<Animation>();
}
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
}
}