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

382 lines
14 KiB
C#
Raw Permalink Normal View History

2025-01-25 04:38:09 +08:00
using UnityEngine;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;
namespace Thousandto.Cinematic
{
//剧情对象序列化以及对clip的增删改
[Serializable]
public class CinematicSerialize : ICinematic
{
public List<CinematicObj> ObjList = new List<CinematicObj>();
public int FrameRate = 30;
public CinematicSerialize()
{
}
public void WriteAll(string clipName)
{
//事先计算一些数据保存下来
HandleDataBeforeSave();
PrepareWrite(clipName);
WriteList(ObjList);
WriteInt(FrameRate);
EndWrite();
}
public void ReadAll(string clipName)
{
PrepareRead(clipName);
ObjList = ReadList<CinematicObj>();
FrameRate = ReadInt();
EndRead();
}
//保存前,处理数据,做一些事先计算
public void HandleDataBeforeSave()
{
for(int i = 0; i < ObjList.Count; ++i)
{
var keyframeList = ObjList[i].KeyframeList;
List<CinematicKeyframe> transEventDataList = new List<CinematicKeyframe>();
List<Vector3> positionList = new List<Vector3>();
for(int m = 0; m < keyframeList.Count; ++m)
{
var eventDataList = keyframeList[m].EventData;
CinematicEventData data = null;
bool hasSyncEvent = false;
for(int n = 0; n < eventDataList.Count; ++n)
{
var oneEvent = eventDataList[n];
if(oneEvent.EventTypeEx == KeyFrameEvent.)
{
keyframeList[m].TransformEvent = oneEvent;
keyframeList[m].TransPercentageInCurve = 0;
transEventDataList.Add(keyframeList[m]);
//positionList.Add(oneEvent.Position);
data = oneEvent;
}
//需要同步的时候,忽略当前关键帧的位移事件
if (oneEvent.EventTypeEx == KeyFrameEvent. ||
oneEvent.EventTypeEx == KeyFrameEvent.)
{
hasSyncEvent = true;
break;
}
}
if(!hasSyncEvent && data != null)
positionList.Add(data.Position);
}
if (positionList.Count > 1)
{
ObjList[i].PathV3Array = PathControlPointGenerator(positionList.ToArray());
CalcPercentageEachPath(positionList.ToArray(), transEventDataList);
}
else
{
ObjList[i].PathV3Array = positionList.ToArray();
}
}
}
//andeeee from the Unity forum's steller Catmull-Rom class ( http://forum.unity3d.com/viewtopic.php?p=218400#218400 ):
public static Vector3 Interp(Vector3[] pts, float t)
{
if (pts.Length == 1) return pts[0];
int numSections = pts.Length - 3;
int currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1);
float u = t * (float)numSections - (float)currPt;
Vector3 a = pts[currPt];
Vector3 b = pts[currPt + 1];
Vector3 c = pts[currPt + 2];
Vector3 d = pts[currPt + 3];
return .5f * (
(-a + 3f * b - 3f * c + d) * (u * u * u)
+ (2f * a - 5f * b + 4f * c - d) * (u * u)
+ (-a + c) * u
+ 2f * b
);
}
private static void CalcPercentageEachPath(Vector3[] path, List<CinematicKeyframe> keyFrameListWithTransEvent)
{
if (path.Length < 2) return;
Vector3[] vector3s = PathControlPointGenerator(path);
//Line Draw:
Vector3 prevPt = Interp(vector3s, 0);
int SmoothAmount = path.Length * 100;
int index = 1;
float allDistance = 0;
for (int i = 1; i <= SmoothAmount; i++)
{
float pm = (float)i / SmoothAmount;
Vector3 currPt = Interp(vector3s, pm);
//与上一个差值点的距离
float disPrev = Vector3.Distance(currPt, prevPt);
allDistance += disPrev;
if (currPt.x == path[index].x && currPt.y == path[index].y && currPt.z == path[index].z)
{
keyFrameListWithTransEvent[index].TransPercentageInCurve = pm;
index++;
}
else
{
int tempIndex = index;
//这里写成循环,是避免下一个关键帧和当前关键帧在同一个位置
for(; tempIndex < path.Length; ++tempIndex)
{
float keyDis = Vector3.Distance(currPt, path[tempIndex]);
if (keyDis <= disPrev)
{
float curPm = pm * (allDistance + keyDis) / allDistance;
keyFrameListWithTransEvent[index].TransPercentageInCurve = curPm;
index = tempIndex + 1;
}
else
break;
}
}
if (index >= path.Length)
{
keyFrameListWithTransEvent[index - 1].TransPercentageInCurve = 1;
return;
}
prevPt = currPt;
}
}
public static Vector3[] PathControlPointGenerator(Vector3[] path)
{
Vector3[] suppliedPath;
Vector3[] vector3s;
//create and store path points:
suppliedPath = path;
//populate calculate path;
int offset = 2;
vector3s = new Vector3[suppliedPath.Length + offset];
Array.Copy(suppliedPath, 0, vector3s, 1, suppliedPath.Length);
//populate start and end control points:
//vector3s[0] = vector3s[1] - vector3s[2];
vector3s[0] = vector3s[1] + (vector3s[1] - vector3s[2]);
vector3s[vector3s.Length - 1] = vector3s[vector3s.Length - 2] + (vector3s[vector3s.Length - 2] - vector3s[vector3s.Length - 3]);
//is this a closed, continuous loop? yes? well then so let's make a continuous Catmull-Rom spline!
if (vector3s[1] == vector3s[vector3s.Length - 2])
{
Vector3[] tmpLoopSpline = new Vector3[vector3s.Length];
Array.Copy(vector3s, tmpLoopSpline, vector3s.Length);
tmpLoopSpline[0] = tmpLoopSpline[tmpLoopSpline.Length - 3];
tmpLoopSpline[tmpLoopSpline.Length - 1] = tmpLoopSpline[2];
vector3s = new Vector3[tmpLoopSpline.Length];
Array.Copy(tmpLoopSpline, vector3s, tmpLoopSpline.Length);
}
return (vector3s);
}
public static void BinarySerialize(string clipName, List<CinematicObj> ObjList, int frameRate = 30)
{
if (ObjList == null || ObjList.Count == 0) return;
CinematicSerialize cs = new CinematicSerialize();
cs.FrameRate = frameRate;
cs.ObjList = ObjList;
cs.WriteAll(clipName);
}
public static CinematicSerialize BinaryDeserialize(string clipName)
{
CinematicSerialize cs = new CinematicSerialize();
try
{
cs.ReadAll(clipName);
}
catch (Exception) {
UnityEngine.Debug.LogWarning("Load cinematic fail, may be not exist! clipName = " + clipName);
cs.EndRead();
}
return cs;
}
public static void SerializeEx(string fileName, CinematicSerialize cs)
{
if (cs.ObjList == null || cs.ObjList.Count == 0) return;
string path = _rootPath + "/" + fileName + _extension;
Dictionary<string, object> data = cs.Serialize();
if (File.Exists(path)) File.Delete(path);
FileStream fileStream = File.OpenWrite(path);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(fileStream, data);
fileStream.Close();
}
/// <summary>
/// 将自定义数据类型转换成基础类型保存,便于跨项目使用
/// </summary>
/// <param name="fileName"></param>
/// <param name="ObjList"></param>
/// <param name="frameRate"></param>
public static void SerializeEx(string fileName, List<CinematicObj> ObjList, int frameRate = 30)
{
if (ObjList == null || ObjList.Count == 0) return;
CinematicSerialize cs = new CinematicSerialize();
cs.FrameRate = frameRate;
cs.ObjList = ObjList;
string path = _rootPath + "/" + fileName + _extension;
SerializeEx(fileName, cs);
}
/// <summary>
/// 读取基础数据类型,然后转换成自定义类型
/// </summary>
/// <param name="fileName"></param>
/// <returns></returns>
public static CinematicSerialize DeserializeEx(string fileName)
{
string path = _rootPath + "/" + fileName + _extension;
Dictionary<string, object> data;
FileStream fileStream = null;
CinematicSerialize cs = new CinematicSerialize();
try
{
fileStream = new FileStream(path, FileMode.Open);
BinaryFormatter b = new BinaryFormatter();
data = b.Deserialize(fileStream) as Dictionary<string, object>;
cs = cs.Deserialize(data) as CinematicSerialize;
}
catch (Exception)
{
cs.ObjList = new List<CinematicObj>();
}
finally
{
if (fileStream != null) fileStream.Close();
}
for(int i = 0; i < cs.ObjList.Count; ++i)
{
cs.ObjList[i].SortKeyframe();
}
return cs;
}
public static void Serialize(string fileName, CinematicSerialize cs)
{
if (cs.ObjList == null || cs.ObjList.Count == 0) return;
string path = _rootPath + "/" + fileName + _extension;
FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate);
BinaryFormatter b = new BinaryFormatter();
b.Serialize(fileStream, cs);
fileStream.Close();
}
public static void Serialize(string fileName, List<CinematicObj> ObjList, int frameRate = 30)
{
if (ObjList == null || ObjList.Count == 0) return;
CinematicSerialize cs = new CinematicSerialize();
cs.FrameRate = frameRate;
cs.ObjList = ObjList;
string path = _rootPath + "/" + fileName + _extension;
Serialize(fileName, cs);
}
public static CinematicSerialize Deserialize(string fileName)
{
string path = _rootPath + "/" + fileName + _extension;
CinematicSerialize ret = null;
FileStream fileStream = null;
try
{
fileStream = new FileStream(path, FileMode.OpenOrCreate);
BinaryFormatter b = new BinaryFormatter();
ret = b.Deserialize(fileStream) as CinematicSerialize;
}
catch(Exception)
{
}
finally
{
if(ret == null)
{
ret = new CinematicSerialize();
ret.ObjList = new List<CinematicObj>();
}
if (fileStream != null) fileStream.Close();
}
return ret;
}
public static void CreateEmptyFile(string fileName)
{
string path = _rootPath + "/" + fileName + _extension;
if(!File.Exists(path))
{
File.Create(path).Close();
}
}
public static void RenameFile(string fileName, string newFileName)
{
string oldPath = _rootPath + "/" + fileName + _extension;
string newPath = _rootPath + "/" + newFileName + _extension;
if (!File.Exists(oldPath)) return;
if (fileName == newFileName) return;
File.Copy(oldPath, newPath, true);
File.Delete(oldPath);
}
public static void DeleteFile(string fileName)
{
string path = _rootPath + "/" + fileName + _extension;
if(File.Exists(path))
{
File.Delete(path);
}
}
//获取所有剧情文件
public static List<string> GetAllCinematicFiles()
{
string path = _rootPath;
List<string> retList = new List<string>();
string[] fileArray = Directory.GetFiles(path, "*" + _extension);
for(int i = 0; i < fileArray.Length; ++i)
{
retList.Add(Path.GetFileNameWithoutExtension(fileArray[i]));
}
return retList;
}
}
}