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

546 lines
24 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;
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;
}
}
}