250 lines
8.9 KiB
C#
250 lines
8.9 KiB
C#
using Convention;
|
|
using Demo.Editor.UI;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Demo.Game
|
|
{
|
|
public abstract class Updatement<DataType> : TimelineScriptObject
|
|
{
|
|
[Serializable]
|
|
public class UpdatementEntry
|
|
{
|
|
public float TimePoint = 0;
|
|
public DataType Position = default;
|
|
public MathExtension.EaseCurveType easeCurveType = MathExtension.EaseCurveType.Linear;
|
|
}
|
|
|
|
public int Content = 0;
|
|
public 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 UpdateEntry(int start, float percent)
|
|
{
|
|
UpdatementEntry head = Entries[start], tail = Entries[Mathf.Min(start + 1, Entries.Count - 1)];
|
|
UpdateData(Lerp(head.Position, tail.Position, MathExtension.Evaluate(Mathf.Clamp01(percent), head.easeCurveType)));
|
|
}
|
|
|
|
protected override IEnumerator DoSomethingDuringApplyScript()
|
|
{
|
|
yield return base.DoSomethingDuringApplyScript();
|
|
Entries.Sort((x, y) => x.TimePoint.CompareTo(y.TimePoint));
|
|
if (UpdateTarget == null)
|
|
{
|
|
UpdateTarget = Parent.gameObject;
|
|
}
|
|
}
|
|
|
|
public override void ResetEnterGameStatus()
|
|
{
|
|
base.ResetEnterGameStatus();
|
|
UpdateEntry(0, 0);
|
|
}
|
|
|
|
public override IEnumerator UnloadScript()
|
|
{
|
|
Content = 0;
|
|
Entries.Clear();
|
|
yield return base.UnloadScript();
|
|
}
|
|
|
|
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
|
|
{
|
|
using (Profiler.BeginZone($"Updatement<{typeof(DataType).Name}>.UpdateTicks"))
|
|
{
|
|
base.UpdateTicks(currentTime, deltaTime, tickType);
|
|
|
|
float GetPercentValue()
|
|
{
|
|
return (currentTime - Entries[Content].TimePoint) / (Entries[Content + 1].TimePoint - Entries[Content].TimePoint);
|
|
}
|
|
|
|
if (Entries.Count <= 1)
|
|
return;
|
|
switch (tickType)
|
|
{
|
|
case TickType.Reset:
|
|
case TickType.Start:
|
|
{
|
|
Content = 0;
|
|
while (Content + 1 < Entries.Count && Entries[Content + 1].TimePoint < currentTime)
|
|
Content++;
|
|
UpdateEntry(Content, GetPercentValue());
|
|
}
|
|
break;
|
|
default:
|
|
if (Entries[0].TimePoint > currentTime)
|
|
return;
|
|
if (Content + 1 >= Entries.Count)
|
|
return;
|
|
if (Entries[Content + 1].TimePoint < currentTime)
|
|
Content++;
|
|
if (Content + 1 >= Entries.Count)
|
|
UpdateEntry(Content, 1);
|
|
else
|
|
UpdateEntry(Content, GetPercentValue());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public DataType Evaluate(float time)
|
|
{
|
|
if (Entries.Count == 0)
|
|
return default;
|
|
if (Entries.Count == 1)
|
|
return Entries[0].Position;
|
|
if (time < Entries[0].TimePoint)
|
|
return Entries[0].Position;
|
|
for (int i = 1; i < Entries.Count; i++)
|
|
{
|
|
if (Entries[i - 1].TimePoint <= time && Entries[i].TimePoint > time)
|
|
{
|
|
return Lerp(Entries[i - 1].Position, Entries[i].Position,
|
|
(time - Entries[i - 1].TimePoint) / (Entries[i].TimePoint - Entries[i - 1].TimePoint));
|
|
}
|
|
}
|
|
return Entries[^1].Position;
|
|
}
|
|
|
|
[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 (Entries.Count == 0)
|
|
return;
|
|
|
|
item.SetupDuration(new(Entries[0].TimePoint, Entries[^1].TimePoint), GetTimelineItemColor());
|
|
}
|
|
}
|
|
|
|
public interface ILocalUpdatement<DataType>: IScriptableObject
|
|
{
|
|
int Content { get; set; }
|
|
public List<ILocalUpdatementExtension.UpdatementEntry<DataType>> Entries { get; set; }
|
|
void UpdateData(DataType data);
|
|
DataType Lerp(DataType begin, DataType end, float t);
|
|
}
|
|
|
|
public static class ILocalUpdatementExtension
|
|
{
|
|
[Serializable]
|
|
public class UpdatementEntry<DataType>
|
|
{
|
|
public float TimePoint = 0;
|
|
public DataType Position = default;
|
|
public MathExtension.EaseCurveType easeCurveType = MathExtension.EaseCurveType.Linear;
|
|
}
|
|
|
|
public static void AddEntry<DataType>(this ILocalUpdatement<DataType> self, float time, DataType position, MathExtension.EaseCurveType curveType)
|
|
{
|
|
self.Entries.Add(new()
|
|
{
|
|
TimePoint = time,
|
|
Position = position,
|
|
easeCurveType = curveType
|
|
});
|
|
}
|
|
|
|
public static void UpdateEntry<DataType>(this ILocalUpdatement<DataType> self, int start, float percent)
|
|
{
|
|
UpdatementEntry<DataType> head = self.Entries[start], tail = self.Entries[Mathf.Min(start + 1, self.Entries.Count - 1)];
|
|
self.UpdateData(self.Lerp(head.Position, tail.Position, MathExtension.Evaluate(Mathf.Clamp01(percent), head.easeCurveType)));
|
|
}
|
|
|
|
public static void LoadScriptHelper<DataType>(this ILocalUpdatement<DataType> self)
|
|
{
|
|
if (self.Entries.Count < 2)
|
|
{
|
|
self.Entries = new()
|
|
{
|
|
new()
|
|
{
|
|
TimePoint=0,
|
|
Position=default,
|
|
},
|
|
new()
|
|
{
|
|
TimePoint = float.MaxValue,
|
|
Position=default,
|
|
}
|
|
};
|
|
}
|
|
else
|
|
{
|
|
self.Entries.Sort((x, y) => x.TimePoint.CompareTo(y.TimePoint));
|
|
}
|
|
}
|
|
|
|
public static void UnloadScriptHelper<DataType>(this ILocalUpdatement<DataType> self)
|
|
{
|
|
self.Content = 0;
|
|
self.Entries = new();
|
|
}
|
|
public static void UpdateTicks<DataType>(this ILocalUpdatement<DataType> self, float currentTime, ScriptableObject.TickType tickType)
|
|
{
|
|
switch (tickType)
|
|
{
|
|
case ScriptableObject.TickType.Pause:
|
|
//case TickType.LateUpdate:
|
|
break;
|
|
case ScriptableObject.TickType.Reset:
|
|
case ScriptableObject.TickType.Start:
|
|
{
|
|
self.Content = 0;
|
|
while (self.Entries[self.Content + 1].TimePoint < currentTime)
|
|
self.Content++;
|
|
UpdateEntry(self, self.Content, 0);
|
|
}
|
|
break;
|
|
default:
|
|
if (self.Entries[0].TimePoint > currentTime)
|
|
return;
|
|
if (self.Content + 1 >= self.Entries.Count)
|
|
return;
|
|
if (self.Entries[self.Content + 1].TimePoint < currentTime)
|
|
self.Content++;
|
|
if (self.Content + 1 >= self.Entries.Count)
|
|
UpdateEntry(self, self.Content, 1);
|
|
else
|
|
UpdateEntry(self, self.Content,
|
|
(currentTime - self.Entries[self.Content].TimePoint) /
|
|
(self.Entries[self.Content + 1].TimePoint - self.Entries[self.Content].TimePoint));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|