using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Ichni.RhythmGame { public class TrackTimeSubmodule : TrackSubmodule { #region [暴露属性字段] Config public float headPercent, tailPercent; #endregion #region [生命周期] Initialization public TrackTimeSubmodule(Track track) : base(track) { if (!HaveSameSubmodule) { this.track.trackTimeSubmodule = this; } } #endregion } #region [派生类] Movable Submodule public class TrackTimeSubmoduleMovable : TrackTimeSubmodule { #region [暴露属性字段] Movable Configs public float trackStartTime; public float trackEndTime; public float trackTotalTime; public float visibleTrackTimeLength; public AnimationCurveType animationCurveType; private const float ClipChangeEpsilon = 0.0001f; private bool hasClipState; private float lastClipFrom; private float lastClipTo; #endregion #region [生命周期] Initialization public TrackTimeSubmoduleMovable(Track track, float trackStartTime, float trackEndTime, float visibleTrackTimeLength, AnimationCurveType animationCurveType) : base(track) { this.trackStartTime = trackStartTime; this.trackEndTime = trackEndTime; this.trackTotalTime = trackEndTime - trackStartTime; this.visibleTrackTimeLength = visibleTrackTimeLength; this.animationCurveType = animationCurveType; //timeDurationSubmodule 根据下辖Note的时间来设置 } #endregion #region [时间运算逻辑] Timing Calculation public void UpdateTrackPart(float songTime) { CalculateVisibleClip(songTime, out float newTailPercent, out float newHeadPercent); headPercent = newHeadPercent; tailPercent = newTailPercent; TrackRendererSubmodule rendererSubmodule = track.trackRendererSubmodule; if (rendererSubmodule == null || rendererSubmodule.meshGenerator == null) { return; } bool clipChanged = !hasClipState || Mathf.Abs(lastClipFrom - tailPercent) > ClipChangeEpsilon || Mathf.Abs(lastClipTo - headPercent) > ClipChangeEpsilon; bool rebuildRequested = rendererSubmodule.ConsumeMeshRebuildRequest(); if (!clipChanged && !rebuildRequested) { return; } rendererSubmodule.meshGenerator.clipFrom = tailPercent; rendererSubmodule.meshGenerator.clipTo = headPercent; rendererSubmodule.meshGenerator.RebuildImmediate(); hasClipState = true; lastClipFrom = tailPercent; lastClipTo = headPercent; //track.trackPathSubmodule.path.Rebuild(true); } private void CalculateVisibleClip(float songTime, out float tailPercent, out float headPercent) { if (songTime <= trackStartTime) { tailPercent = 0f; headPercent = 0f; return; } if (songTime >= trackEndTime + visibleTrackTimeLength) { tailPercent = 1f; headPercent = 1f; return; } headPercent = GetTrackPercent(songTime); tailPercent = GetTrackPercent(songTime - visibleTrackTimeLength); } public float GetTrackPercent(float songTimeInTime) { float per = AnimationCurveEvaluator.Evaluate(animationCurveType, (songTimeInTime - trackStartTime) / trackTotalTime); return Mathf.Clamp01(per); } #endregion #region [行为重写] Behavior Overrides public override void Refresh() { trackTotalTime = trackEndTime - trackStartTime; UpdateTrackPart(CoreServices.TimeProvider.SongTime); track.childElementList.ForEach(child => { if (child is NoteBase note) { note.UpdateNoteInTrack(CoreServices.TimeProvider.SongTime); } }); } #endregion } #endregion #region [派生类] Static Submodule public class TrackTimeSubmoduleStatic : TrackTimeSubmodule { #region [暴露属性字段] Static Configs public float trackTotalTime; public AnimationCurveType animationCurveType; #endregion #region [生命周期] Initialization public TrackTimeSubmoduleStatic(Track track, float trackTotalTime, AnimationCurveType animationCurveType) : base(track) { this.trackTotalTime = trackTotalTime; this.animationCurveType = animationCurveType; this.headPercent = 0; this.tailPercent = 1; //timeDurationSubmodule 根据下辖Note的时间来设置 } #endregion #region [行为重写] Behavior Overrides public override void Refresh() { track.childElementList.ForEach(child => { if (child is NoteBase note) { note.UpdateNoteInTrack(CoreServices.TimeProvider.SongTime); } }); } #endregion } #endregion }