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

546 lines
24 KiB
C#
Raw Permalink Normal View History

2025-01-25 04:38:09 +08:00
using UnityEngine;
using Thousandto.Core.Asset;
using System;
using System.Collections.Generic;
namespace Thousandto.Cinematic
{
//剧情对象管理,流程管理
public class CinematicObjManager
{
private CinematicObj _cObj;
private FGameObjectVFXBox _vfxbox = new FGameObjectVFXBox();
//上一个含有位移事件的关键帧
private CinematicKeyframe _preTransKeyframe;
//上一个含有动画世界的关键帧
private CinematicKeyframe _preAnimKeyframe;
//上一个同步事件关键帧
private CinematicKeyframe _preKeyframeWithSyncEvent;
private int _curFrame;
private float _framesAfterPreKey;
public static bool IsEditorPreview;
//剧情播放前的场景音效
private string _lastSceneMusicName = null;
//正在播放的音效
private int _playingSpeech = -1;
private int _playingSfx = -1;
public void Prepare(CinematicObj obj)
{
_curFrame = -1;
_cObj = obj;
_preTransKeyframe = null;
_cObj.Prepare();
}
public void Destory()
{
_vfxbox.Clear();
if (_cObj != null) _cObj.Destory();
StopCinematicAudio();
}
public int GetCurFrame()
{
return _curFrame;
}
public Dictionary<int, string> GetVfxDatas()
{
Dictionary<int, string> vfxResDict = new Dictionary<int, string>();
var keyframeList = _cObj.KeyframeList;
for(int i = 0; i < keyframeList.Count; ++i)
{
int keyframe = keyframeList[i].Keyframe;
var eventDatas = keyframeList[i].EventData;
for(int j = 0; j < eventDatas.Count; ++j)
{
if(eventDatas[j].EventTypeEx == KeyFrameEvent. ||
eventDatas[j].EventTypeEx == KeyFrameEvent.)
{
if (vfxResDict.ContainsKey(keyframe))
vfxResDict[keyframe] = eventDatas[j].Param;
else
vfxResDict.Add(keyframe, eventDatas[j].Param);
}
}
}
return vfxResDict;
}
public bool IsEnd(int frameNum)
{
return _cObj == null || _cObj.IsEndFrame(frameNum);
}
//frameNum 当前第几帧
public void Update(int frameNum)
{
if (_cObj == null) return;
Update();
var curFrameData = _cObj.GetKeyframeData(frameNum);
if(curFrameData != null)
{
//上一个同步帧
if (curFrameData.HasSyncTrans)
_preKeyframeWithSyncEvent = curFrameData;
if (curFrameData.TransformEvent != null)
{
//直到走到有位移的帧,同步帧置空
_preTransKeyframe = curFrameData;
_preKeyframeWithSyncEvent = null;
}
if (curFrameData.AnimEvent != null)
_preAnimKeyframe = curFrameData;
}
else if (frameNum < _curFrame)
{
_preTransKeyframe = _cObj.GetPreTransKeyframeData(frameNum);
_preAnimKeyframe = _cObj.GetPreAnimKeyframeData(frameNum);
_preKeyframeWithSyncEvent = null;
}
_curFrame = frameNum;
if (_preTransKeyframe == null && curFrameData == null && _preAnimKeyframe == null && _preKeyframeWithSyncEvent == null) return;
//处理当前帧数据
HandleCurFrameData(curFrameData);
//如果当前帧没数据,则处理前后帧的位移
if (_preTransKeyframe != null)
{
//当前帧与上一个关键帧的偏移量
_framesAfterPreKey = frameNum - _preTransKeyframe.Keyframe;
HandleTransform(_preTransKeyframe, _framesAfterPreKey);
}
if (_preAnimKeyframe != null)
{
HandleAnimation(_preAnimKeyframe, _curFrame);
}
//开始时候同步位置
if(_preKeyframeWithSyncEvent != null && _preKeyframeWithSyncEvent.HasSyncTrans && _preKeyframeWithSyncEvent.PreEventData == null)
{
float durationFrame = _preKeyframeWithSyncEvent.NextTransKeyframe.Keyframe - _preKeyframeWithSyncEvent.Keyframe;
float deltaFrame = frameNum - _preKeyframeWithSyncEvent.Keyframe;
_cObj.SetTransform(_preKeyframeWithSyncEvent.TransformEvent, _preKeyframeWithSyncEvent.NextTransKeyframe.TransformEvent, durationFrame, deltaFrame);
}
//结束前同步位置
if (_preTransKeyframe != null &&
_preTransKeyframe.NextKeyframe != null &&
_preTransKeyframe.NextKeyframe.HasSyncTrans)
{
//if (_preTransKeyframe.NextKeyframe.TransformEvent == null)
{
_preTransKeyframe.NextKeyframe.NeedSetPositionNow = false;
PreHandleSyncEvent(_preTransKeyframe.NextKeyframe);
}
float durationFrame = _preTransKeyframe.NextKeyframe.Keyframe - _preTransKeyframe.Keyframe;
float deltaFrame = frameNum - _preTransKeyframe.Keyframe;
//上一个位移帧的位移,移动到当前帧上面存放的需要同步的位置
_cObj.SetTransform(_preTransKeyframe.TransformEvent, _preTransKeyframe.NextKeyframe.TransformEvent, durationFrame, deltaFrame);
}
}
//小于1帧需要平滑设置位移和动画效果
public void UpdateSmooth(float deltaFrameLessThanOne)
{
//如果当前帧没数据,则处理前后帧的位移
if (_preTransKeyframe != null)
{
//当前帧与上一个关键帧的偏移量
_framesAfterPreKey = _curFrame + deltaFrameLessThanOne - _preTransKeyframe.Keyframe;
HandleTransform(_preTransKeyframe, _framesAfterPreKey);
}
if (_preAnimKeyframe != null)
{
HandleAnimation(_preAnimKeyframe, _curFrame + deltaFrameLessThanOne);
}
}
public void Update()
{
if (_cObj != null) _cObj.Update();
_vfxbox.Update(Time.deltaTime);
}
private void HandleCurFrameData(CinematicKeyframe curFrame)
{
for (int i = 0; curFrame != null && i < curFrame.EventData.Count; ++i)
{
curFrame.EventData[i].ParentGo = _cObj.GameObject;
curFrame.EventData[i].CinematicObj = _cObj;
//跟随相机事件后续的事件都不做处理
if (_cObj.IsFollowCamera &&
curFrame.EventData[i].EventTypeEx != KeyFrameEvent. &&
curFrame.EventData[i].EventTypeEx != KeyFrameEvent. &&
curFrame.EventData[i].EventTypeEx != KeyFrameEvent. &&
curFrame.EventData[i].EventTypeEx != KeyFrameEvent.)
continue;
if (curFrame.EventData[i].EventTypeEx == KeyFrameEvent.)
_cObj.IsFollowCamera = true;
switch (curFrame.EventData[i].EventTypeEx)
{
case KeyFrameEvent.:
if (!HandleEvent(KeyFrameEvent., curFrame.EventData[i]))
_cObj.LoadPrefab(curFrame.EventData[i].Param, curFrame.EventData[i].EditorParam);
break;
case KeyFrameEvent.:
_cObj.SetTransform(curFrame.EventData[i]);
_cObj.ResetTransState();
//设置下一个同步事件
//if(curFrame.NextTransKeyframe != null && curFrame.NextTransKeyframe.HasSyncTrans)
//{
// if(_cObj.IsCamera)
// {
// HandleEvent(KeyFrameEvent.同步到本地相机坐标, curFrame.NextTransKeyframe);
// }
// else
// {
// HandleEvent(KeyFrameEvent.同步到本地角色坐标, curFrame.NextTransKeyframe);
// }
//}
break;
case KeyFrameEvent.:
{
var vfx = new FGameObjectVFX();
vfx.Initialize(curFrame.EventData[i].Param.Replace("\\", "/"), true, false);
vfx.SetParent(_cObj.GameObject.transform, true);
vfx.SetLayer(LayerUtils.Default);
vfx.Play(1);
_vfxbox.Add(vfx);
//Debug.LogError("播放场景特效:" + _cObj.GameObject.name + ";;;" + curFrame.EventData[i].Param);
}
break;
case KeyFrameEvent.:
if (!HandleEvent(KeyFrameEvent., curFrame.EventData[i]))
{
_cObj.PlayAnimation(curFrame.EventData[i]);
//UnityEngine.Debug.LogError("handle KeyFrameEvent.PlayAnim fail, please check!!!");
}
break;
case KeyFrameEvent.:
{
var vfx = new FGameObjectVFX();
vfx.Initialize(curFrame.EventData[i].Param.Replace("\\", "/"), true, false);
vfx.SetParent(_cObj.GameObject.transform, true);
if(_cObj.IsCamera)
{
var cam = _cObj.GameObject.GetComponent<Camera>();
if(cam != null)
Plugins.Common.UniScene.BaseScene.FixCameraVfx(vfx, cam);
}
vfx.SetLayer(LayerUtils.Default);
vfx.Play(1);
_vfxbox.Add(vfx);
//Debug.LogError("播放绑定特效:" + _cObj.GameObject.name+ ";;;"+ curFrame.EventData[i].Param);
}
//VFXPlayer.SyncPlayOnTransform(curFrame.EventData[i].Param, _cObj.GameObject.transform, LayerUtils.UIRoleStory);
break;
case KeyFrameEvent.:
if(System.Enum.IsDefined(typeof(AudioTypeCode), curFrame.EventData[i].EditorParam))
{
var type = (AudioTypeCode)System.Enum.Parse(typeof(AudioTypeCode), curFrame.EventData[i].EditorParam);
PlayAudio(type, null, curFrame.EventData[i].Param);
}
break;
case KeyFrameEvent.:
if (System.Enum.IsDefined(typeof(AudioTypeCode), curFrame.EventData[i].EditorParam))
{
var type = (AudioTypeCode)System.Enum.Parse(typeof(AudioTypeCode), curFrame.EventData[i].EditorParam);
PlayAudio(type, _cObj.GameObject, curFrame.EventData[i].Param);
}
break;
case KeyFrameEvent.:
float pauseFrame;
if(float.TryParse(curFrame.EventData[i].Param, out pauseFrame))
{
CinematicManager.PauseFrame = pauseFrame;
}
break;
case KeyFrameEvent.: //显示或隐藏
_cObj.GameObject.SetActive(!curFrame.EventData[i].IsLocalPlayer);
break;
case KeyFrameEvent.: //绑定坐骑
if(!HandleEvent(KeyFrameEvent., curFrame.EventData[i]))
UnityEngine.Debug.LogError("请先运行游戏才能显示绑定的坐骑");
break;
case KeyFrameEvent.: //同步本地相机位置
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能SyncLocalCameraTrans");
_preKeyframeWithSyncEvent = curFrame;
_cObj.SetCameraVisiable();
break;
case KeyFrameEvent.: //同步本地角色位置
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能SyncLocalCameraTrans");
_preKeyframeWithSyncEvent = curFrame;
break;
case KeyFrameEvent.: //同步本地角色位置到剧情
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能LocalCameraSyncTrans");
break;
case KeyFrameEvent.: //同步本地角色位置到剧情
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能LocalPlayerSyncTrans");
break;
case KeyFrameEvent.: //时间缩放
float scale = 0;
if(float.TryParse(curFrame.EventData[i].Param, out scale))
{
if (scale <= 0) scale = 0.1f;
if (scale >= 2) scale = 2.0f;
CinematicManager.Instance.TimeScale = scale;
Time.timeScale = scale;
}
break;
case KeyFrameEvent.:
OnCinematicShakeObj(curFrame.EventData[i]);
break;
case KeyFrameEvent.:
CameraBlurEffect(_cObj.GameObject, curFrame.EventData[i]);
break;
case KeyFrameEvent.:
CameraBlackTransEffect(_cObj.GameObject, curFrame.EventData[i]);
break;
case KeyFrameEvent.:
_cObj.LoadPrefabFromScene(curFrame.EventData[i].Param);
break;
//UI效果+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
case KeyFrameEvent.:
case KeyFrameEvent.boss名字:
case KeyFrameEvent.Texture:
case KeyFrameEvent.Texture:
case KeyFrameEvent.UI特效:
case KeyFrameEvent.UI特效:
case KeyFrameEvent.:
case KeyFrameEvent.:
case KeyFrameEvent.:
case KeyFrameEvent.:
case KeyFrameEvent.UI图片Alpha效果:
case KeyFrameEvent.:
if (!HandleEvent(KeyFrameEvent.UI效果, curFrame.EventData[i]))
UnityEngine.Debug.LogError("请先运行游戏才能显示Texture");
break;
//------------------------------------------------------------------
default:
HandleEvent(curFrame.EventData[i].EventTypeEx, curFrame.EventData[i]);
break;
}
}
}
private void PlayAudio(AudioTypeCode type, GameObject target, string audioName)
{
switch(type)
{
case AudioTypeCode.Ambient:
AudioPlayer.PlayAmbient(target, audioName);
break;
case AudioTypeCode.Music:
{
if (string.IsNullOrEmpty(_lastSceneMusicName))
_lastSceneMusicName = AudioPlayer.GetPlayingMusicName();
AudioPlayer.PlayMusic(audioName, true);
}
break;
case AudioTypeCode.Sfx:
_playingSfx = AudioPlayer.PlaySfx(target, audioName);
break;
case AudioTypeCode.Speech:
_playingSpeech = AudioPlayer.PlaySpeech(target, audioName);
break;
case AudioTypeCode.UI:
AudioPlayer.PlayUI(audioName);
break;
}
}
public void StopCinematicAudio()
{
AudioPlayer.ChannelManager.Stop(_playingSfx);
AudioPlayer.ChannelManager.Stop(_playingSpeech);
//恢复之前的背景音乐
if (!string.IsNullOrEmpty(_lastSceneMusicName))
AudioPlayer.PlayMusic(_lastSceneMusicName, true);
_lastSceneMusicName = null;
}
//预处理同步事件,需要事先获取下一帧同步的位置,不然没有位移变换
private void PreHandleSyncEvent(CinematicKeyframe curFrame)
{
for(int i = 0; i < curFrame.EventData.Count; ++i)
{
var eventData = curFrame.EventData[i];
switch(eventData.EventTypeEx)
{
case KeyFrameEvent.: //同步本地相机位置
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能SyncLocalCameraTrans");
_preKeyframeWithSyncEvent = curFrame;
_cObj.SetCameraVisiable();
break;
case KeyFrameEvent.: //同步本地角色位置
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能SyncLocalCameraTrans");
_preKeyframeWithSyncEvent = curFrame;
break;
case KeyFrameEvent.: //同步本地角色位置到剧情
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能LocalCameraSyncTrans");
break;
case KeyFrameEvent.: //同步本地角色位置到剧情
if (!HandleEvent(KeyFrameEvent., curFrame))
UnityEngine.Debug.LogError("请先运行游戏才能LocalPlayerSyncTrans");
break;
}
}
}
//处理事件
private bool HandleEvent(KeyFrameEvent eventType, ICinematic eventData)
{
bool ret = false;
Func<ICinematic, bool> handler = CinematicManager.Instance.GetEventHandler(eventType);
if (handler != null)
{
ret = handler(eventData);
}
return ret;
}
//处理位移
private void HandleTransform(CinematicKeyframe frameWithTransData, float frameDelta)
{
if (frameDelta == 0) return;
if(frameWithTransData.TransformEvent == null)
{
for (int i = 0; frameWithTransData != null && i < frameWithTransData.EventData.Count; ++i)
{
if(frameWithTransData.EventData[i].EventTypeEx == KeyFrameEvent.)
{
frameWithTransData.TransformEvent = frameWithTransData.EventData[i];
break;
}
}
}
if(frameWithTransData.TransformEvent != null)
{
var nextKeyframe = frameWithTransData.NextKeyframe;
//下一个关键帧是同步帧,则不做曲线变换,直接跳过
if (nextKeyframe != null && nextKeyframe.HasSyncTrans)
{
//if(nextKeyframe.TransformEvent == null)
PreHandleSyncEvent(nextKeyframe);
return;
}
_cObj.SetTransformCurveTo(frameWithTransData.TransformEvent, frameWithTransData, frameWithTransData.Keyframe, frameDelta);
}
}
//处理动作,逐帧播放的动作
private void HandleAnimation(CinematicKeyframe frameWithAnimData, float curFrame)
{
if(frameWithAnimData.AnimEvent == null)
{
for (int i = 0; frameWithAnimData != null && i < frameWithAnimData.EventData.Count; ++i)
{
switch (frameWithAnimData.EventData[i].EventTypeEx)
{
case KeyFrameEvent.:
frameWithAnimData.AnimEvent = frameWithAnimData.EventData[i];
break;
default:
break;
}
}
}
_cObj.PlayAnimationByFrame(frameWithAnimData.AnimEvent, frameWithAnimData.Keyframe, curFrame);
}
//运动模糊效果
private void CameraBlurEffect(GameObject cameraGo, CinematicEventData eventData)
{
float duration = 0;
float strenth = 3;
if (!float.TryParse(eventData.Param, out duration))
{
duration = 2.0f;
}
if (!float.TryParse(eventData.EditorParam, out strenth))
{
strenth = 3f;
}
var blurScript = RequireComponent<CinematicSportBlur>(_cObj.GameObject);
blurScript.StartBlur(duration, strenth);
}
//相机渐黑效果
private void CameraBlackTransEffect(GameObject cameraGo, CinematicEventData eventData)
{
float duration = 0;
if (!float.TryParse(eventData.Param, out duration))
{
duration = 2.0f;
}
var script = RequireComponent<CinematicFadeBlack>(_cObj.GameObject);
script.StartTrans(duration);
}
//振动效果
public bool OnCinematicShakeObj(CinematicEventData eventData)
{
float duration = 0;
float strenth = 3;
if (!float.TryParse(eventData.Param, out duration))
{
duration = 2.0f;
}
if (!float.TryParse(eventData.EditorParam, out strenth))
{
strenth = 3f;
}
var shakeScript = RequireComponent<CinematicShake>(eventData.ParentGo);
shakeScript.StartShake(duration, strenth);
return true;
}
private T RequireComponent<T>(GameObject go) where T: MonoBehaviour
{
T script = go.GetComponent<T>();
if (script == null)
script = go.AddComponent<T>();
return script;
}
}
}