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

352 lines
9.6 KiB
C#
Raw 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;
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);
}
}
}
}
}