324 lines
7.4 KiB
C#
324 lines
7.4 KiB
C#
|
|
using System.Diagnostics;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
using Godot;
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
public class TimeLineRunner
|
|
{
|
|
public TimeLine timeLine;
|
|
public TimeLineManager manager;
|
|
|
|
public float lastPosition = 0;
|
|
public float position = 0;
|
|
public bool playing = false;
|
|
public float deltaScale = 1;
|
|
public float speed = 1;
|
|
|
|
List<TimeLineEvent> events = new List<TimeLineEvent>();
|
|
List<TimeLineSpan> spans = new List<TimeLineSpan>();
|
|
List<TimeLineCallback> callbacks = new List<TimeLineCallback>();
|
|
|
|
AnimationCurve modulatorCurve;
|
|
float modulatorTime;
|
|
Vector3 modulatorRandomization;
|
|
Action<bool> modulatorOnReady = null;
|
|
float _lastModulation = 1;
|
|
float _currentDelta = 1;
|
|
|
|
public float modulatedSpeed => (float)( speed * _lastModulation * deltaScale );
|
|
public float currentDelta => _currentDelta;
|
|
|
|
public TimeLineRunner( TimeLine timeLine, TimeLineManager manager )
|
|
{
|
|
this.timeLine = timeLine;
|
|
this.manager = manager;
|
|
|
|
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 )
|
|
{
|
|
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;
|
|
}
|
|
|
|
_currentDelta = realtimeDelta * deltaScale * speed * modulation;
|
|
lastPosition = position;
|
|
position += _currentDelta;
|
|
|
|
var isForward = speed >= 0;
|
|
|
|
if ( isForward )
|
|
{
|
|
ProcessForward();
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ProcessForward()
|
|
{
|
|
ProcessEvents();
|
|
ProcessSpans();
|
|
ProcessCallbacks();
|
|
}
|
|
|
|
List<TimeLineCallback> _callbackAdditions = new List<TimeLineCallback>();
|
|
|
|
void ProcessCallbacks()
|
|
{
|
|
if ( _callbackAdditions.Count > 0 )
|
|
{
|
|
callbacks.AddRange( _callbackAdditions );
|
|
_callbackAdditions.Clear();
|
|
}
|
|
|
|
callbacks.ForEach( c => c.callback( c ) );
|
|
|
|
|
|
}
|
|
|
|
void ProcessEvents()
|
|
{
|
|
if ( requestedRemovals.Count > 0 )
|
|
{
|
|
requestedRemovals.Sort();
|
|
Lists.RemoveIncreasingSortedIndices( events, requestedRemovals );
|
|
requestedRemovals.Clear();
|
|
}
|
|
|
|
List<int> eventRemovals = null;
|
|
|
|
for ( int i = 0; i < events.Count; i++ )
|
|
{
|
|
var eventPosition = events[ i ].position;
|
|
|
|
if ( events[ i ].looping )
|
|
{
|
|
var next = events[ i ].GetNextLoopPosition( lastPosition );
|
|
var previous = events[ i ].GetPreviousLoopPosition( position );
|
|
|
|
if ( next != previous )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
eventPosition = next;
|
|
}
|
|
|
|
if ( ! RangeDouble.ContainsExclusiveMax( lastPosition, position, eventPosition ) )
|
|
{
|
|
if ( events[ i ].wasInside )
|
|
{
|
|
eventRemovals = AddRemoval( events[ i ].persistent, i, eventRemovals );
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
events[ i ].callback( events[ i ] );
|
|
events[ i ].wasInside = true;
|
|
|
|
}
|
|
|
|
if ( eventRemovals != null )
|
|
{
|
|
Lists.RemoveIncreasingSortedIndices( events, eventRemovals );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
void ProcessSpans()
|
|
{
|
|
if ( spans.Count == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
List<int> spanRemovals = null;
|
|
|
|
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 );
|
|
|
|
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 = TimeLineSpanUpdateType.InSpan;
|
|
|
|
if ( isStart && isEnd )
|
|
{
|
|
spanType = TimeLineSpanUpdateType.CompletelyInside;
|
|
}
|
|
else if ( isStart )
|
|
{
|
|
spanType = TimeLineSpanUpdateType.Start;
|
|
}
|
|
else if ( isEnd )
|
|
{
|
|
spanType = TimeLineSpanUpdateType.End;
|
|
}
|
|
|
|
spans[ i ].wasInside = true;
|
|
|
|
spans[ i ].callback( spans[ i ], spanType );
|
|
|
|
}
|
|
|
|
if ( spanRemovals != null )
|
|
{
|
|
Lists.RemoveIncreasingSortedIndices( spans, spanRemovals );
|
|
}
|
|
}
|
|
|
|
|
|
List<int> AddRemoval( bool isPersistent, int index, List<int> list )
|
|
{
|
|
if ( isPersistent )
|
|
{
|
|
return list;
|
|
}
|
|
|
|
if ( list == null )
|
|
{
|
|
list = new List<int>();
|
|
}
|
|
|
|
list.Add( index );
|
|
|
|
return list;
|
|
}
|
|
|
|
List<int> requestedRemovals = new List<int>();
|
|
|
|
public void RemoveEvent( int eventID )
|
|
{
|
|
requestedRemovals.Add( eventID );
|
|
}
|
|
|
|
public TimeLineCallback _ScheduleCallback( Action<TimeLineCallback> callback, int eventID )
|
|
{
|
|
var tle = new TimeLineCallback();
|
|
tle.id = eventID;
|
|
tle.callback = callback;
|
|
tle.timeLine = timeLine;
|
|
|
|
_callbackAdditions.Add( tle );
|
|
|
|
return tle;
|
|
}
|
|
|
|
public TimeLineEvent _ScheduleEvent( float position, int eventID, bool isPersistent, Action<TimeLineEvent> callback )
|
|
{
|
|
var tle = new TimeLineEvent();
|
|
tle.position = position;
|
|
tle.id = eventID;
|
|
tle.persistent = isPersistent;
|
|
tle.callback = callback;
|
|
tle.timeLine = timeLine;
|
|
|
|
events.Add( tle );
|
|
|
|
return tle;
|
|
}
|
|
|
|
public TimeLineEvent _ScheduleLoopEvent( float loopDuration, float loopOffset, int eventID, bool isPersistent, Action<TimeLineEvent> callback )
|
|
{
|
|
var tle = new TimeLineEvent();
|
|
tle.position = loopOffset;
|
|
tle.looping = true;
|
|
tle.loopDuration = loopDuration;
|
|
tle.id = eventID;
|
|
tle.persistent = isPersistent;
|
|
tle.callback = callback;
|
|
tle.timeLine = timeLine;
|
|
events.Add( tle );
|
|
|
|
return tle;
|
|
}
|
|
|
|
public TimeLineSpan _ScheduleSpan( float start, float end, int eventID, bool isPersistent, Action<TimeLineSpan, TimeLineSpanUpdateType> callback )
|
|
{
|
|
var tse = new TimeLineSpan();
|
|
tse.start = start;
|
|
tse.end = end;
|
|
tse.id = eventID;
|
|
tse.persistent = isPersistent;
|
|
tse.wasInside = false;
|
|
tse.callback = callback;
|
|
tse.timeLine = timeLine;
|
|
|
|
spans.Add( tse );
|
|
|
|
return tse;
|
|
}
|
|
}
|
|
} |