rj-action-library/Runtime/Time/TimeLineRunner.cs

242 lines
5.6 KiB
C#
Raw Normal View History

2024-05-19 15:59:41 +00:00
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<TimeLineEvent> events = new List<TimeLineEvent>();
List<TimeLineSpan> spans = new List<TimeLineSpan>();
2025-01-03 12:09:23 +00:00
AnimationCurve modulatorCurve;
float modulatorTime;
Vector3 modulatorRandomization;
Action<bool> modulatorOnReady = null;
float _lastModulation = 1;
public float modulatedSpeed => (float)( speed * _lastModulation * deltaScale );
2024-05-19 15:59:41 +00:00
public TimeLineRunner( RJTimeLine timeLine )
{
this.timeLine = timeLine;
playing = timeLine.AutoStart;
}
2025-01-03 12:09:23 +00:00
public void Modulate( AnimationCurve curve, Action<bool> onReady )
{
if ( modulatorOnReady != null )
{
modulatorOnReady( false );
}
modulatorCurve = curve;
modulatorTime = 0;
modulatorRandomization = curve.Randomize();
modulatorOnReady = onReady;
}
public void UpdateTimeLine( float realtimeDelta, TimeLineManager manager )
2024-05-19 15:59:41 +00:00
{
if ( ! playing )
{
return;
}
2025-01-03 12:09:23 +00:00
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;
}
2024-05-19 15:59:41 +00:00
lastPosition = position;
2025-01-03 12:09:23 +00:00
position += realtimeDelta * deltaScale * speed * modulation;
2024-05-19 15:59:41 +00:00
var isForward = speed >= 0;
if ( isForward )
{
ProcessForward( manager );
}
}
2025-01-03 12:09:23 +00:00
List<int> AddRemoval( bool isPersistent, int i, List<int> list )
{
if ( isPersistent )
{
return list;
}
if ( list == null )
{
list = new List<int>();
}
list.Add( i );
return list;
}
2024-05-19 15:59:41 +00:00
void ProcessForward( TimeLineManager manager )
{
List<int> eventRemovals = null;
List<int> spanRemovals = null;
2025-01-03 12:09:23 +00:00
var scheduler = Unique<TimeLineScheduler>.Get();
2024-05-19 15:59:41 +00:00
for ( int i = 0; i < events.Count; i++ )
{
var eventPosition = events[ i ].position;
2025-01-03 12:09:23 +00:00
// 0 1 2 3 4 5
// Last 3, Position 4
//
2024-05-19 15:59:41 +00:00
if ( ! RangeDouble.ContainsExclusiveMax( lastPosition, position, eventPosition ) )
{
2025-01-03 12:09:23 +00:00
if ( events[ i ].wasInside )
{
eventRemovals = AddRemoval( events[ i ].persistent, i, eventRemovals );
}
2024-05-19 15:59:41 +00:00
continue;
}
RJLog.Log( "Emitting:",
"last:", lastPosition,
"now:", position,
"event:", eventPosition
);
manager.EmitSignal( TimeLineManager.SignalName.OnEvent, events[ i ].id );
2025-01-03 12:09:23 +00:00
events[ i ].wasInside = true;
2024-05-19 15:59:41 +00:00
}
if ( eventRemovals != null )
{
2025-01-03 12:09:23 +00:00
eventRemovals.ForEach( ev => scheduler._RemoveEventEntry( ev ) );
Lists.RemoveIncreasingSortedIndices( events, eventRemovals );
2024-05-19 15:59:41 +00:00
}
if ( spans.Count == 0 )
{
return;
}
var timelineSpan = new RangeDouble( lastPosition, position );
var span = new RangeDouble( 0, 1 );
2025-01-03 12:09:23 +00:00
var isForward = lastPosition < position;
2024-05-19 15:59:41 +00:00
for ( int i = 0; i < spans.Count; i++ )
{
span.min = spans[ i ].start;
span.max = spans[ i ].end;
2025-01-03 12:09:23 +00:00
var overlaps = timelineSpan.Overlaps( span );
// RJLog.Log( "Span", i, overlaps, spans[ i ].id, ">>", spans[ i ].start, spans[ i ].end, "||", lastPosition, position );
if ( ! overlaps )
2024-05-19 15:59:41 +00:00
{
2025-01-03 12:09:23 +00:00
if ( spans[ i ].wasInside )
{
spanRemovals = AddRemoval( spans[ i ].persistent, i, spanRemovals );
}
2024-05-19 15:59:41 +00:00
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;
}
2025-01-03 12:09:23 +00:00
spans[ i ].wasInside = true;
manager.EmitSignal( TimeLineManager.SignalName.OnSpan, spans[ i ].id, spanType );
2024-05-19 15:59:41 +00:00
2025-01-03 12:09:23 +00:00
}
2024-05-19 15:59:41 +00:00
2025-01-03 12:09:23 +00:00
if ( spanRemovals != null )
{
spanRemovals.ForEach( ev => scheduler._RemoveSpanEntry( ev ) );
Lists.RemoveIncreasingSortedIndices( spans, spanRemovals );
2024-05-19 15:59:41 +00:00
}
}
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 );
}
}
}