using System.Diagnostics; using System.Collections; using System.Collections.Generic; using System; using Godot; namespace Rokojori { public class TimeLineRunner { public RJTimeLine timeLine; public double lastPosition = 0; public double position = 0; public bool playing = false; public double deltaScale = 1; public double speed = 1; List events = new List(); List spans = new List(); AnimationCurve modulatorCurve; float modulatorTime; Vector3 modulatorRandomization; Action modulatorOnReady = null; float _lastModulation = 1; public float modulatedSpeed => (float)( speed * _lastModulation * deltaScale ); public TimeLineRunner( RJTimeLine timeLine ) { this.timeLine = timeLine; playing = timeLine.AutoStart; } public void Modulate( AnimationCurve curve, Action onReady ) { if ( modulatorOnReady != null ) { modulatorOnReady( false ); } modulatorCurve = curve; modulatorTime = 0; modulatorRandomization = curve.Randomize(); modulatorOnReady = onReady; } public void UpdateTimeLine( float realtimeDelta, TimeLineManager manager ) { if ( ! playing ) { return; } var modulation = 1f; if ( modulatorCurve != null ) { modulation = modulatorCurve.Sample( modulatorTime, modulatorRandomization ); _lastModulation = modulation; modulatorTime += realtimeDelta; if ( modulatorTime >= modulatorCurve.GetRandomizedEndTime( modulatorRandomization ) ) { var mr = modulatorOnReady; modulatorOnReady = null; modulatorCurve = null; modulatorTime = 0; modulatorRandomization = Vector3.Zero; if ( mr != null ) { mr( true ); } } } else { _lastModulation = 1; } lastPosition = position; position += realtimeDelta * deltaScale * speed * modulation; var isForward = speed >= 0; if ( isForward ) { ProcessForward( manager ); } } List AddRemoval( bool isPersistent, int i, List list ) { if ( isPersistent ) { return list; } if ( list == null ) { list = new List(); } list.Add( i ); return list; } void ProcessForward( TimeLineManager manager ) { List eventRemovals = null; List spanRemovals = null; var scheduler = Unique.Get(); for ( int i = 0; i < events.Count; i++ ) { var eventPosition = events[ i ].position; // 0 1 2 3 4 5 // Last 3, Position 4 // if ( ! RangeDouble.ContainsExclusiveMax( lastPosition, position, eventPosition ) ) { if ( events[ i ].wasInside ) { eventRemovals = AddRemoval( events[ i ].persistent, i, eventRemovals ); } continue; } RJLog.Log( "Emitting:", "last:", lastPosition, "now:", position, "event:", eventPosition ); manager.EmitSignal( TimeLineManager.SignalName.OnEvent, events[ i ].id ); events[ i ].wasInside = true; } if ( eventRemovals != null ) { eventRemovals.ForEach( ev => scheduler._RemoveEventEntry( ev ) ); Lists.RemoveIncreasingSortedIndices( events, eventRemovals ); } if ( spans.Count == 0 ) { return; } var timelineSpan = new RangeDouble( lastPosition, position ); var span = new RangeDouble( 0, 1 ); var isForward = lastPosition < position; for ( int i = 0; i < spans.Count; i++ ) { span.min = spans[ i ].start; span.max = spans[ i ].end; var overlaps = timelineSpan.Overlaps( span ); // RJLog.Log( "Span", i, overlaps, spans[ i ].id, ">>", spans[ i ].start, spans[ i ].end, "||", lastPosition, position ); if ( ! overlaps ) { if ( spans[ i ].wasInside ) { spanRemovals = AddRemoval( spans[ i ].persistent, i, spanRemovals ); } continue; } var isStart = timelineSpan.Contains( spans[ i ].start ); var isEnd = timelineSpan.Contains( spans[ i ].end ); var spanType = TimeLineSpan.InSpan; if ( isStart && isEnd ) { spanType = TimeLineSpan.CompletelyInside; } else if ( isStart ) { spanType = TimeLineSpan.Start; } else if ( isEnd ) { spanType = TimeLineSpan.End; } spans[ i ].wasInside = true; manager.EmitSignal( TimeLineManager.SignalName.OnSpan, spans[ i ].id, spanType ); } if ( spanRemovals != null ) { spanRemovals.ForEach( ev => scheduler._RemoveSpanEntry( ev ) ); Lists.RemoveIncreasingSortedIndices( spans, spanRemovals ); } } public void ScheduleEvent( double position, int callbackID, bool isPersistent ) { var tle = new TimeLineEvent(); tle.position = position; tle.id = callbackID; tle.persistent = isPersistent; events.Add( tle ); } public void ScheduleSpan( double start, double end, int callbackID, bool isPersistent ) { var tse = new TimeLineSpan(); tse.start = start; tse.end = end; tse.id = callbackID; tse.persistent = isPersistent; tse.wasInside = false; spans.Add( tse ); } } }