Files

284 lines
12 KiB
C#

using Convention;
using Demo.Editor.UI;
using Demo.Game.ConfigType;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Unity.Collections;
using UnityEngine;
namespace Demo.Game
{
namespace ConfigType
{
public abstract class UpdatementConfig<DataType>: ScriptLoadableConfig where DataType : struct
{
public NativeArray<float> TimePoints;
public NativeArray<DataType> Positions;
public NativeArray<MathExtension.EaseCurveType> EaseCurveTypes;
protected abstract void DeserializePositions(BinaryReader reader, ref NativeArray<DataType> positions);
protected abstract void SerializePositions(BinaryWriter writer, in NativeArray<DataType> positions);
public override void Deserialize(BinaryReader reader)
{
BinarySerializeUtility.DeserializeNativeArray(reader, ref TimePoints);
DeserializePositions(reader, ref Positions);
{
NativeArray<int> temp = new(EaseCurveTypes.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
BinarySerializeUtility.DeserializeNativeArray(reader, ref temp);
for (int i = 0, e = EaseCurveTypes.Length; i < e; i++)
{
EaseCurveTypes[i] = (MathExtension.EaseCurveType)temp[i];
}
temp.Dispose();
}
base.Deserialize(reader);
}
public override void Serialize(BinaryWriter writer)
{
BinarySerializeUtility.SerializeNativeArray(writer, TimePoints);
SerializePositions(writer, Positions);
{
NativeArray<int> temp = new(EaseCurveTypes.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
for (int i = 0, e = EaseCurveTypes.Length; i < e; i++)
{
temp[i] = (int)EaseCurveTypes[i];
}
BinarySerializeUtility.SerializeNativeArray(writer, temp);
temp.Dispose();
}
base.Serialize(writer);
}
}
public class UpdatementIntConfig : UpdatementConfig<int>
{
protected override sealed void DeserializePositions(BinaryReader reader, ref NativeArray<int> positions)
{
BinarySerializeUtility.DeserializeNativeArray(reader, ref positions);
}
protected override sealed void SerializePositions(BinaryWriter writer, in NativeArray<int> positions)
{
BinarySerializeUtility.SerializeNativeArray(writer, positions);
}
}
public class UpdatementFloatConfig : UpdatementConfig<float>
{
protected override sealed void DeserializePositions(BinaryReader reader, ref NativeArray<float> positions)
{
BinarySerializeUtility.DeserializeNativeArray(reader, ref positions);
}
protected override sealed void SerializePositions(BinaryWriter writer, in NativeArray<float> positions)
{
BinarySerializeUtility.SerializeNativeArray(writer, positions);
}
}
public class UpdatementVec2Config : UpdatementConfig<Vector2>
{
protected override sealed void DeserializePositions(BinaryReader reader, ref NativeArray<Vector2> positions)
{
BinarySerializeUtility.DeserializeNativeArray(reader, ref positions);
}
protected override sealed void SerializePositions(BinaryWriter writer, in NativeArray<Vector2> positions)
{
BinarySerializeUtility.SerializeNativeArray(writer, positions);
}
}
public class UpdatementVec3Config : UpdatementConfig<Vector3>
{
protected override sealed void DeserializePositions(BinaryReader reader, ref NativeArray<Vector3> positions)
{
BinarySerializeUtility.DeserializeNativeArray(reader, ref positions);
}
protected override sealed void SerializePositions(BinaryWriter writer, in NativeArray<Vector3> positions)
{
BinarySerializeUtility.SerializeNativeArray(writer, positions);
}
}
}
public abstract class Updatement<DataType> : TimelineScriptObject where DataType : struct
{
[Serializable]
public class UpdatementEntry
{
public float TimePoint = 0;
public DataType Position = default;
public MathExtension.EaseCurveType easeCurveType = MathExtension.EaseCurveType.Linear;
}
public int Content = 0;
private readonly List<UpdatementEntry> Entries = new();
protected abstract void UpdateData(DataType data);
protected abstract DataType Lerp(DataType begin, DataType end, float t);
/// <summary>
/// 添加数据
/// </summary>
/// <param name="time"></param>
/// <param name="position"></param>
/// <param name="curveType"></param>
public void ManualAddEntry(float time, DataType position, MathExtension.EaseCurveType curveType)
{
Entries.Add(new()
{
TimePoint = time,
Position = position,
easeCurveType = curveType
});
}
private void BuildupCompiledEntriesAndReleaseEntries()
{
Entries.Sort((x, y) => x.TimePoint.CompareTo(y.TimePoint));
GetConfig<UpdatementConfig<DataType>>().TimePoints = new NativeArray<float>(Entries.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
GetConfig<UpdatementConfig<DataType>>().Positions = new NativeArray<DataType>(Entries.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes = new NativeArray<MathExtension.EaseCurveType>(Entries.Count, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
int index = 0;
foreach (var item in Entries)
{
GetConfig<UpdatementConfig<DataType>>().TimePoints[index] = item.TimePoint;
GetConfig<UpdatementConfig<DataType>>().Positions[index] = item.Position;
GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes[index] = item.easeCurveType;
index++;
}
Entries.Clear();
}
private void UpdateEntry(int start, float percent)
{
int head = start;
int tail = Mathf.Min(start + 1, GetConfig<UpdatementConfig<DataType>>().TimePoints.Length - 1);
UpdateData(Lerp(GetConfig<UpdatementConfig<DataType>>().Positions[start],
GetConfig<UpdatementConfig<DataType>>().Positions[tail],
MathExtension.Evaluate(Mathf.Clamp01(percent), GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes[head])));
}
protected override IEnumerator DoSomethingDuringApplyScript()
{
yield return base.DoSomethingDuringApplyScript();
BuildupCompiledEntriesAndReleaseEntries();
if (UpdateTarget == null)
{
UpdateTarget = Parent.gameObject;
}
}
public override void ResetEnterGameStatus()
{
base.ResetEnterGameStatus();
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.Length <= 1)
return;
UpdateEntry(0, 0);
}
public override IEnumerator UnloadScript()
{
Content = 0;
GetConfig<UpdatementConfig<DataType>>().TimePoints.Dispose();
GetConfig<UpdatementConfig<DataType>>().Positions.Dispose();
GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes.Dispose();
yield return base.UnloadScript();
}
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
{
base.UpdateTicks(currentTime, deltaTime, tickType);
float GetPercentValue()
{
if (Content + 1 == GetConfig<UpdatementConfig<DataType>>().TimePoints.Length)
return 1;
return (currentTime - GetConfig<UpdatementConfig<DataType>>().TimePoints[Content]) / (GetConfig<UpdatementConfig<DataType>>().TimePoints[Content + 1] - GetConfig<UpdatementConfig<DataType>>().TimePoints[Content]);
}
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.Length <= 1)
return;
switch (tickType)
{
case TickType.Reset:
case TickType.Start:
{
Content = 0;
while (Content + 1 < GetConfig<UpdatementConfig<DataType>>().TimePoints.Length && GetConfig<UpdatementConfig<DataType>>().TimePoints[Content + 1] < currentTime)
Content++;
UpdateEntry(Content, GetPercentValue());
}
break;
default:
if (GetConfig<UpdatementConfig<DataType>>().TimePoints[0] > currentTime)
return;
if (Content + 1 < GetConfig<UpdatementConfig<DataType>>().TimePoints.Length && GetConfig<UpdatementConfig<DataType>>().TimePoints[Content + 1] < currentTime)
Content++;
if (Content + 1 > GetConfig<UpdatementConfig<DataType>>().TimePoints.Length)
return;
UpdateEntry(Content, GetPercentValue());
break;
}
}
public DataType Evaluate(float time)
{
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.Length == 0)
return default;
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.Length == 1)
return GetConfig<UpdatementConfig<DataType>>().Positions[0];
if (time < GetConfig<UpdatementConfig<DataType>>().TimePoints[0])
return GetConfig<UpdatementConfig<DataType>>().Positions[0];
for (int i = 1; i < GetConfig<UpdatementConfig<DataType>>().TimePoints.Length; i++)
{
if (GetConfig<UpdatementConfig<DataType>>().TimePoints[i - 1] <= time && GetConfig<UpdatementConfig<DataType>>().TimePoints[i] > time)
{
return Lerp(GetConfig<UpdatementConfig<DataType>>().Positions[i - 1], GetConfig<UpdatementConfig<DataType>>().Positions[i],
(time - GetConfig<UpdatementConfig<DataType>>().TimePoints[i - 1]) /
(GetConfig<UpdatementConfig<DataType>>().TimePoints[i] - GetConfig<UpdatementConfig<DataType>>().TimePoints[i - 1]));
}
}
return GetConfig<UpdatementConfig<DataType>>().Positions[^1];
}
[Content] public GameObject UpdateTarget;
/// <summary>
/// 设置更新对象
/// </summary>
[Convention.RScript.Variable.Attr.Method]
public void SetUpdateTarget(ScriptableObject target)
{
UpdateTarget = target.gameObject;
}
/// <summary>
///
/// </summary>
/// <param name="item">实例在父类中控制</param>
protected override void SetupTimelineItem(TimelineItem item)
{
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.Length == 0)
return;
item.SetupDuration(new(GetConfig<UpdatementConfig<DataType>>().TimePoints[0], GetConfig<UpdatementConfig<DataType>>().TimePoints[^1]), GetTimelineItemColor());
}
private void OnDestroy()
{
if (GetConfig<UpdatementConfig<DataType>>().TimePoints.IsCreated)
GetConfig<UpdatementConfig<DataType>>().TimePoints.Dispose();
if (GetConfig<UpdatementConfig<DataType>>().Positions.IsCreated)
GetConfig<UpdatementConfig<DataType>>().Positions.Dispose();
if (GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes.IsCreated)
GetConfig<UpdatementConfig<DataType>>().EaseCurveTypes.Dispose();
}
}
}