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

382 lines
14 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.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;
}
}
}