Files
Convention-Unity-Demo/Assets/Scripts/Framework/Updatement.cs

253 lines
8.9 KiB
C#
Raw Normal View History

2025-09-25 19:04:05 +08:00
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Convention;
using Demo.Editor.UI;
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 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(string time, DataType position, MathExtension.EaseCurveType curveType)
{
Entries.Add(new()
{
TimePoint = Parse(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)));
}
public override IEnumerator LoadScript(string script)
{
yield return base.LoadScript(script);
Entries.Sort((x, y) => x.TimePoint.CompareTo(y.TimePoint));
if (UpdateTarget == null)
{
UpdateTarget = transform.parent.gameObject;
}
}
public override void ResetEnterGameStatus()
{
base.ResetEnterGameStatus();
UpdateEntry(0, 0);
}
2025-09-25 19:04:05 +08:00
public override IEnumerator UnloadScript()
{
Content = 0;
Entries = new();
yield return base.UnloadScript();
}
protected override void UpdateTicks(float currentTime, float deltaTime, TickType tickType)
{
base.UpdateTicks(currentTime, deltaTime, tickType);
float GetPercentValue()
{
return (currentTime - Entries[Content].TimePoint) / (Entries[Content + 1].TimePoint - Entries[Content].TimePoint);
}
if (Entries.Count <= 1)
2025-09-25 19:04:05 +08:00
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());
2025-09-25 19:04:05 +08:00
}
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());
2025-09-25 19:04:05 +08:00
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>
/// <param name="path">脚本的相对路径</param>
[Convention.RScript.Variable.Attr.Method]
2025-09-25 19:04:05 +08:00
public void SetUpdateTarget(string path)
{
var temp = FindWithPath(path);
if (temp != null)
UpdateTarget = temp.gameObject;
else
Debug.LogWarning($"{path}' is not found", this);
}
/// <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, string time, DataType position, MathExtension.EaseCurveType curveType)
{
self.Entries.Add(new()
{
TimePoint = self.SharedInterfaceScriptObject.Parse(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;
}
}
}
}