242 lines
5.6 KiB
C#
242 lines
5.6 KiB
C#
|
|
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>();
|
|
|
|
AnimationCurve modulatorCurve;
|
|
float modulatorTime;
|
|
Vector3 modulatorRandomization;
|
|
Action<bool> 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<bool> 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<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;
|
|
}
|
|
|
|
|
|
void ProcessForward( TimeLineManager manager )
|
|
{
|
|
List<int> eventRemovals = null;
|
|
List<int> spanRemovals = null;
|
|
|
|
var scheduler = Unique<TimeLineScheduler>.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 );
|
|
}
|
|
}
|
|
} |