352 lines
9.6 KiB
C#
352 lines
9.6 KiB
C#
|
using UnityEngine;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System;
|
|||
|
|
|||
|
namespace Thousandto.Cinematic
|
|||
|
{
|
|||
|
//剧情对象
|
|||
|
public partial class CinematicManager
|
|||
|
{
|
|||
|
#region //私有变量
|
|||
|
private List<CinematicObjManager> _cObjMgrList;
|
|||
|
private float _startTime;
|
|||
|
private int _curFrame;
|
|||
|
//剧情播放前
|
|||
|
private Action _afterAction;
|
|||
|
//剧情播放后
|
|||
|
private Action _beforeAction;
|
|||
|
private bool _isPlaying;
|
|||
|
private bool _isEditorPlay = false;
|
|||
|
//自定义事件处理函数
|
|||
|
private Dictionary<int, Func<ICinematic, bool>> _customEventHandlerDict;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region //公有变量
|
|||
|
public int FrameRate = 30;
|
|||
|
public float TimeScale = 1f;
|
|||
|
|
|||
|
//每一帧改变
|
|||
|
public Action<int> OnFrameUpdate;
|
|||
|
#endregion
|
|||
|
|
|||
|
#region //静态成员、静态属性
|
|||
|
private static string _rootName = "[CinematicRoot]";
|
|||
|
private static GameObject _rootGo;
|
|||
|
|
|||
|
//暂停帧数
|
|||
|
public static float PauseFrame;
|
|||
|
public static bool IsEditorPreview;
|
|||
|
|
|||
|
private static CinematicManager _instance;
|
|||
|
public static CinematicManager Instance
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if(_instance == null)
|
|||
|
{
|
|||
|
_instance = new CinematicManager();
|
|||
|
}
|
|||
|
|
|||
|
return _instance;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public static GameObject RootGo
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (_rootGo == null)
|
|||
|
{
|
|||
|
_rootGo = GameObject.Find(_rootName);
|
|||
|
if (_rootGo == null)
|
|||
|
{
|
|||
|
_rootGo = new GameObject(_rootName);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return _rootGo;
|
|||
|
}
|
|||
|
}
|
|||
|
#endregion
|
|||
|
|
|||
|
public void RemoveAllChild()
|
|||
|
{
|
|||
|
for(int i = RootGo.transform.childCount - 1; i >= 0; --i)
|
|||
|
{
|
|||
|
GameObject.DestroyImmediate(RootGo.transform.GetChild(i).gameObject);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void Destroy()
|
|||
|
{
|
|||
|
RemoveAllChild();
|
|||
|
GameObject.DestroyImmediate(RootGo);
|
|||
|
}
|
|||
|
|
|||
|
private void Reset()
|
|||
|
{
|
|||
|
if(_cObjMgrList != null)
|
|||
|
{
|
|||
|
for(int i = 0; i < _cObjMgrList.Count; ++i)
|
|||
|
{
|
|||
|
_cObjMgrList[i].Destory();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
_cObjMgrList = null;
|
|||
|
_timer = 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
public void RegisterHandler(KeyFrameEvent eventType, Func<ICinematic, bool> handler)
|
|||
|
{
|
|||
|
if (_customEventHandlerDict == null)
|
|||
|
_customEventHandlerDict = new Dictionary<int, Func<ICinematic, bool>>();
|
|||
|
|
|||
|
if (_customEventHandlerDict.ContainsKey((int)eventType))
|
|||
|
_customEventHandlerDict[(int)eventType] = handler;
|
|||
|
else
|
|||
|
_customEventHandlerDict.Add((int)eventType, handler);
|
|||
|
}
|
|||
|
|
|||
|
public Func<ICinematic, bool> GetEventHandler(KeyFrameEvent eventType)
|
|||
|
{
|
|||
|
Func<ICinematic, bool> handler = null;
|
|||
|
if (_customEventHandlerDict != null)
|
|||
|
_customEventHandlerDict.TryGetValue((int)eventType, out handler);
|
|||
|
|
|||
|
return handler;
|
|||
|
}
|
|||
|
|
|||
|
//返回剧情数据
|
|||
|
public List<CinematicObjManager> GetCinematicDatas()
|
|||
|
{
|
|||
|
return _cObjMgrList;
|
|||
|
}
|
|||
|
|
|||
|
public void Play(string clipName, Action before, Action after)
|
|||
|
{
|
|||
|
//先清空之前的残余数据
|
|||
|
Reset();
|
|||
|
_beforeAction = before;
|
|||
|
_afterAction = after;
|
|||
|
_isEditorPlay = false;
|
|||
|
PauseFrame = 0;
|
|||
|
|
|||
|
BeforePlay();
|
|||
|
|
|||
|
var cs = CinematicSerialize.BinaryDeserialize(clipName);
|
|||
|
FrameRate = cs.FrameRate;
|
|||
|
if (cs.ObjList.Count > 0)
|
|||
|
{
|
|||
|
_cObjMgrList = new List<CinematicObjManager>();
|
|||
|
for (int i = 0; i < cs.ObjList.Count; ++i)
|
|||
|
{
|
|||
|
CinematicObjManager cObjM = new CinematicObjManager();
|
|||
|
cObjM.Prepare(cs.ObjList[i]);
|
|||
|
_cObjMgrList.Add(cObjM);
|
|||
|
}
|
|||
|
|
|||
|
_startTime = Time.realtimeSinceStartup;
|
|||
|
_curFrame = -1;
|
|||
|
_isPlaying = true;
|
|||
|
//触发第一帧
|
|||
|
TriggerEvent(1);
|
|||
|
}
|
|||
|
else if (after != null)
|
|||
|
{
|
|||
|
after();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void BeforePlay()
|
|||
|
{
|
|||
|
if (_beforeAction != null) _beforeAction();
|
|||
|
}
|
|||
|
|
|||
|
public void AfterPlay()
|
|||
|
{
|
|||
|
if (_afterAction != null) _afterAction();
|
|||
|
}
|
|||
|
|
|||
|
public void StopPlay()
|
|||
|
{
|
|||
|
Reset();
|
|||
|
_isPlaying = false;
|
|||
|
_isEditorPlay = false;
|
|||
|
TimeScale = 1;
|
|||
|
AfterPlay();
|
|||
|
}
|
|||
|
|
|||
|
//当前帧
|
|||
|
public int GetCurFrame()
|
|||
|
{
|
|||
|
return _curFrame;
|
|||
|
}
|
|||
|
|
|||
|
public bool IsPlaying()
|
|||
|
{
|
|||
|
return _isPlaying;
|
|||
|
}
|
|||
|
|
|||
|
public List<CinematicObjManager> GetObjMgrList()
|
|||
|
{
|
|||
|
return _cObjMgrList;
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
#region //Editor use
|
|||
|
public void ResetEditorPlay()
|
|||
|
{
|
|||
|
if(_cObjMgrList != null && _cObjMgrList.Count > 0)
|
|||
|
{
|
|||
|
for(int i = 0; i < _cObjMgrList.Count; ++i)
|
|||
|
{
|
|||
|
_cObjMgrList[i].Destory();
|
|||
|
}
|
|||
|
}
|
|||
|
_cObjMgrList = null;
|
|||
|
}
|
|||
|
|
|||
|
public void EditorPlay(List<CinematicObj> objList)
|
|||
|
{
|
|||
|
if(_cObjMgrList == null)
|
|||
|
{
|
|||
|
_isEditorPlay = true;
|
|||
|
_cObjMgrList = new List<CinematicObjManager>();
|
|||
|
for (int i = 0; i < objList.Count; ++i)
|
|||
|
{
|
|||
|
CinematicObjManager cObjM = new CinematicObjManager();
|
|||
|
cObjM.Prepare(objList[i]);
|
|||
|
_cObjMgrList.Add(cObjM);
|
|||
|
}
|
|||
|
|
|||
|
_startTime = Time.realtimeSinceStartup;
|
|||
|
_curFrame = -1;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//单帧播放
|
|||
|
public void EditorUpdate(int frame)
|
|||
|
{
|
|||
|
_isPlaying = true;
|
|||
|
|
|||
|
if (_cObjMgrList == null || _cObjMgrList.Count == 0) return;
|
|||
|
for (int i = 0; i < _cObjMgrList.Count; ++i)
|
|||
|
{
|
|||
|
//防止跳帧
|
|||
|
int runningFrame = _cObjMgrList[i].GetCurFrame();
|
|||
|
int frameDelta = Mathf.Abs(frame - runningFrame);
|
|||
|
for (int m = 0; m < frameDelta; ++m)
|
|||
|
{
|
|||
|
if(frame >= runningFrame)
|
|||
|
runningFrame++;
|
|||
|
else
|
|||
|
runningFrame--;
|
|||
|
|
|||
|
_cObjMgrList[i].Update(runningFrame);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
#endif
|
|||
|
|
|||
|
float _timer;
|
|||
|
float _tempFrameRate;
|
|||
|
public void Update()
|
|||
|
{
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (_isEditorPlay) return;
|
|||
|
#endif
|
|||
|
if (!_isPlaying) return;
|
|||
|
|
|||
|
if(_timer == 0)
|
|||
|
{
|
|||
|
_tempFrameRate = FrameRate;
|
|||
|
}
|
|||
|
|
|||
|
if (_cObjMgrList == null || _cObjMgrList.Count == 0) return;
|
|||
|
float nowTime = Time.realtimeSinceStartup;
|
|||
|
float deltaTime = nowTime - _startTime;
|
|||
|
//float deltaTime = Time.deltaTime;
|
|||
|
deltaTime *= TimeScale;
|
|||
|
_timer += deltaTime;
|
|||
|
_startTime = nowTime;
|
|||
|
//暂停时间
|
|||
|
if (PauseFrame > 0)
|
|||
|
{
|
|||
|
_timer -= deltaTime;
|
|||
|
PauseFrame -= deltaTime/TimeScale;
|
|||
|
if (PauseFrame <= 0) PauseFrame = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(_tempFrameRate != FrameRate)
|
|||
|
{
|
|||
|
//消除帧率改变的影响
|
|||
|
_timer -= deltaTime;
|
|||
|
_timer = _tempFrameRate * _timer / FrameRate;
|
|||
|
_timer += deltaTime;
|
|||
|
_tempFrameRate = FrameRate;
|
|||
|
}
|
|||
|
//总共多少帧
|
|||
|
float frames = _timer * FrameRate;
|
|||
|
float deltaFrames = frames - _curFrame;
|
|||
|
int frameCount = (int)(deltaFrames);
|
|||
|
//间隔没有1帧,则返回
|
|||
|
if (frameCount >= 1)
|
|||
|
{
|
|||
|
TriggerEvent(frameCount);
|
|||
|
}
|
|||
|
|
|||
|
if(_isPlaying)
|
|||
|
DoSmoothMove(deltaFrames - frameCount);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void TriggerEvent(int frames)
|
|||
|
{
|
|||
|
bool isAllEnd = true;
|
|||
|
|
|||
|
//防止跳帧
|
|||
|
for (int frame = 0; frame < frames; ++frame)
|
|||
|
{
|
|||
|
isAllEnd = true;
|
|||
|
_curFrame++;
|
|||
|
|
|||
|
if (OnFrameUpdate != null)
|
|||
|
OnFrameUpdate(_curFrame);
|
|||
|
|
|||
|
for (int i = 0; i < _cObjMgrList.Count; ++i)
|
|||
|
{
|
|||
|
|
|||
|
_cObjMgrList[i].Update(_curFrame);
|
|||
|
|
|||
|
isAllEnd &= _cObjMgrList[i].IsEnd(_curFrame);
|
|||
|
}
|
|||
|
if (PauseFrame > 0) return;
|
|||
|
}
|
|||
|
|
|||
|
if (isAllEnd)
|
|||
|
{
|
|||
|
StopPlay();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void DoSmoothMove(float deltaFrame)
|
|||
|
{
|
|||
|
if (PauseFrame == 0 && _cObjMgrList != null)
|
|||
|
{
|
|||
|
for (int i = 0; i < _cObjMgrList.Count; ++i)
|
|||
|
{
|
|||
|
_cObjMgrList[i].UpdateSmooth(deltaFrame);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|