382 lines
14 KiB
C#
382 lines
14 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|
||
|