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