Main/Assets/Plugins/Code/Cinematic/CinematicObj.cs
2025-01-25 04:38:09 +08:00

654 lines
22 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}
}