Files
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

256 lines
9.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using SLSUtilities.General;
using UnityEngine;
namespace SLSUtilities.FunctionalAnimation
{
public class RuntimeFuncAnim
{
public FuncAnimData funcAnimData;
public string animationName => funcAnimData.animInfo.animationName;
public bool isLooping => funcAnimData.animationClip.isLooping;
public IFuncAnimExecutor executor;
public float currentPlayTime;
public float currentTotalPlayTime;
public bool isDisrupted;
public int dataAnimEventIndex;
public int runtimeAnimEventIndex;
public EventCollection dataEvents;
public EventCollection runtimeEvents;
public VariableCollection runtimeVariables;
public Dictionary<string, bool> updateUntilStatus;
private List<FuncAnimEvent> playedEndEvents;
[NonSerialized]
public object currentActionParams;
public RuntimeFuncAnim(FuncAnimData funcAnimData, IFuncAnimExecutor character)
{
this.funcAnimData = funcAnimData;
this.executor = character;
isDisrupted = false;
dataAnimEventIndex = 0;
dataEvents = funcAnimData.eventCollection.Clone();
runtimeEvents = new EventCollection();
updateUntilStatus = new Dictionary<string, bool>();
playedEndEvents = new List<FuncAnimEvent>();
runtimeVariables = funcAnimData.variableCollection!= null ? funcAnimData.variableCollection.Clone() : new VariableCollection();
dataEvents.animEvents.ForEach(animEvt => animEvt.payload.runtimeFuncAnim = this);
dataEvents.animEvents.Sort((evt1, evt2) => evt1.triggerTime.CompareTo(evt2.triggerTime)); //确保动画事件按触发时间排序
dataEvents.startEvents.ForEach(payload => payload.runtimeFuncAnim = this);
dataEvents.disruptionEvents.ForEach(payload => payload.runtimeFuncAnim = this);
dataEvents.updateEvents.ForEach(payload => payload.runtimeFuncAnim = this);
dataEvents.updateUntilEvents.ForEach(payload => payload.runtimeFuncAnim = this);
}
public T GetParams<T>() where T : class
{
if (currentActionParams is T typedParams)
{
return typedParams;
}
Debug.LogWarning(currentActionParams != null
? $"[RuntimeFuncAnim] 参数类型不匹配。期望: {typeof(T).Name}, 实际: {currentActionParams.GetType().Name}"
: $"[RuntimeFuncAnim] 尝试获取 {typeof(T).Name},但当前参数为空。");
return null;
}
public void AddAnimEvent(float time, FuncAnimPayloadBase payload, bool isEnd = false)
{
payload.runtimeFuncAnim = this;
runtimeEvents.animEvents.Add(new FuncAnimEvent(time, payload, isEnd));
}
public void UpdateAnimEvent()
{
while (dataAnimEventIndex < dataEvents.animEvents.Count)
{
FuncAnimEvent animEvent = dataEvents.animEvents[dataAnimEventIndex];
if (currentPlayTime >= animEvent.triggerTime)
{
animEvent.payload.Invoke();
dataAnimEventIndex++;
if (animEvent.isEnd)
{
playedEndEvents.Add(animEvent);
}
}
else
{
break;
}
}
while (runtimeAnimEventIndex < runtimeEvents.animEvents.Count)
{
FuncAnimEvent animEvent = runtimeEvents.animEvents[runtimeAnimEventIndex];
if (currentPlayTime >= animEvent.triggerTime)
{
animEvent.payload.Invoke();
runtimeAnimEventIndex++;
if (animEvent.isEnd)
{
playedEndEvents.Add(animEvent);
}
}
else
{
break;
}
}
}
public void InvokeEndEvents()
{
dataEvents.endEvents.Exclude(playedEndEvents).Invoke();
runtimeEvents.endEvents.Exclude(playedEndEvents).Invoke();
}
public RuntimeFuncAnim AddStartEvent(FuncAnimPayloadBase payload)
{
payload.runtimeFuncAnim = this;
runtimeEvents.startEvents.Add(payload);
return this;
}
public void InvokeStartEvents()
{
dataEvents.startEvents.Invoke();
runtimeEvents.startEvents.Invoke();
}
public RuntimeFuncAnim AddDisruptionEvent(FuncAnimPayloadBase payload)
{
payload.runtimeFuncAnim = this;
runtimeEvents.disruptionEvents.Add(payload);
return this;
}
public void InvokeDisruptionEvents()
{
dataEvents.disruptionEvents.Invoke();
runtimeEvents.disruptionEvents.Invoke();
}
public RuntimeFuncAnim AddUpdateEvent(FuncAnimPayloadBase payload)
{
payload.runtimeFuncAnim = this;
runtimeEvents.updateEvents.Add(payload);
return this;
}
public void InvokeUpdateEvents()
{
dataEvents.updateEvents.Invoke();
runtimeEvents.updateEvents.Invoke();
}
public RuntimeFuncAnim AddUpdateUntilEvent(FuncAnimPayloadBase<bool> payload)
{
payload.runtimeFuncAnim = this;
runtimeEvents.updateUntilEvents.Add(payload);
updateUntilStatus.Add(payload.eventName, false);
return this;
}
public void InvokeUpdateUntilEvents()
{
foreach (FuncAnimPayloadBase<bool> updateUntilEvent in dataEvents.updateUntilEvents)
{
if (!updateUntilStatus[updateUntilEvent.eventName])
{
updateUntilStatus[updateUntilEvent.eventName] = updateUntilEvent.Invoke();
}
}
foreach (FuncAnimPayloadBase<bool> updateUntilEvent in runtimeEvents.updateUntilEvents)
{
if (!updateUntilStatus[updateUntilEvent.eventName])
{
updateUntilStatus[updateUntilEvent.eventName] = updateUntilEvent.Invoke();
}
}
}
public void ClearRuntimeEvents()
{
runtimeEvents.animEvents.Clear();
runtimeEvents.startEvents.Clear();
runtimeEvents.disruptionEvents.Clear();
runtimeEvents.updateEvents.Clear();
runtimeEvents.updateUntilEvents.Clear();
SetUpdateUntilEventsStatus();
}
public void SetUpdateUntilEventsStatus(List<FuncAnimPayloadBase<bool>> events = null)
{
updateUntilStatus.Clear();
if (events == null)
{
foreach (FuncAnimPayloadBase<bool> evt in dataEvents.updateUntilEvents)
{
updateUntilStatus.Add(evt.eventName, false);
}
foreach (FuncAnimPayloadBase<bool> evt in runtimeEvents.updateUntilEvents)
{
updateUntilStatus.Add(evt.eventName, false);
}
}
else
{
foreach (FuncAnimPayloadBase<bool> evt in events)
{
updateUntilStatus.Add(evt.eventName, false);
}
}
}
public void ResetUpdateUntilEventsStatus()
{
List<string> keys = updateUntilStatus.Keys.ToList();
foreach (string key in keys)
{
updateUntilStatus[key] = false;
}
}
public bool HasIntervalType(IntervalType type)
{
if (funcAnimData == null || funcAnimData.intervals == null)
{
Debug.LogWarning($"[FuncAnimData.RuntimeInfo] Parent data or intervals list is null.");
return false;
}
return funcAnimData.intervals.Any(interval => interval.intervalType == type);
}
public List<FuncAnimInterval> GetEnablingIntervals() => GetEnablingIntervals(currentPlayTime);
public List<FuncAnimInterval> GetEnablingIntervals(float time)
{
if (funcAnimData == null || funcAnimData.intervals == null)
{
Debug.LogWarning($"[FuncAnimData.RuntimeInfo] Parent data or intervals list is null.");
return new List<FuncAnimInterval>();
}
return funcAnimData.intervals.Where(interval =>
{
if(Mathf.Approximately(interval.StartTime, interval.EndTime)) return false; //忽略瞬时区间
return time >= interval.StartTime && time <= interval.EndTime; //在区间内
}).ToList();
}
}
}