| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 |
- using UnityEngine;
- using System;
- using System.Reflection;
- using System.Collections.Generic;
- namespace Flux
- {
- [System.Flags]
- public enum CacheMode
- {
- // None = 0,
- Editor = 1,
- RuntimeForward = 2,
- RuntimeBackwards = 4
- }
- /**
- * @brief FTrack holds events of a specific type. You cannot have a track with multiple types of events.
- * You can only have 2 events on the same frame per track, i.e. overlapping start and end.
- * @sa FSequence, FTimeline, FEvent
- */
- public class FTrack : FObject
- {
- // timeline it belongs to
- [SerializeField]
- [HideInInspector]
- private FTimeline _timeline;
- // string of the type of events it holds
- [SerializeField]
- [HideInInspector]
- private string _evtTypeStr;
- // event type, which unfortunately doesn't serialize
- private Type _evtType;
- // events it holds
- [SerializeField]
- [HideInInspector]
- private List<FEvent> _events = new List<FEvent>();
- /// @brief List of events it holds
- public List<FEvent> Events { get { return _events; } }
- public bool RequiresNoCache { get { return CacheMode == 0; } }
- public bool RequiresEditorCache { get { return (CacheMode & CacheMode.Editor) != 0; } }
- public bool RequiresForwardCache { get { return (CacheMode & CacheMode.RuntimeForward) != 0; } }
- public bool RequiresBackwardsCache { get { return (CacheMode & CacheMode.RuntimeBackwards) != 0; } }
- [SerializeField]
- [HideInInspector]
- private CacheMode _cacheMode = 0;
- public CacheMode CacheMode { get { return _cacheMode; } set { _cacheMode = value; } }
- public virtual CacheMode RequiredCacheMode { get { return 0; } }
- public virtual CacheMode AllowedCacheMode { get { return 0; } }
- // keep track of the current event we're updating
- private int _currentEvent = 0;
- /**
- * @brief Creates a FTrack.
- * @param T type of event this track will hold
- */
- public static FTrack Create<T>() where T : FEvent
- {
- Type evtType = typeof(T);
- string evtName = evtType.Name;
- GameObject trackGO = new GameObject( evtName );
- Type trackType = typeof(FTrack);
- #if NETFX_CORE
- System.Attribute[] customAttributes = new List<System.Attribute>(evtType.GetTypeInfo().GetCustomAttributes(typeof(FEventAttribute), false)).ToArray();
- #else
- object[] customAttributes = evtType.GetCustomAttributes(typeof(FEventAttribute), false);
- #endif
- if (customAttributes.Length > 0 )
- {
- trackType = ((FEventAttribute)customAttributes[0]).trackType;
- }
- FTrack track = (FTrack)trackGO.AddComponent(trackType);
- track.SetEventType( evtType );
- track.CacheMode = track.RequiredCacheMode;
- return track;
- }
- // sets the timeline it belongs to, only to be called by FTimeline to avoid errors
- internal void SetTimeline( FTimeline timeline )
- {
- _timeline = timeline;
- if( _timeline )
- {
- transform.parent = _timeline.transform;
- }
- else
- {
- transform.parent = null;
- }
- }
- public override FSequence Sequence { get { return _timeline.Sequence; } }
- public override Transform Owner { get { return _timeline.Owner; } }
- public override void Init()
- {
- _currentEvent = Sequence.IsPlayingForward ? 0 : _events.Count - 1;
- for( int i = 0; i != _events.Count; ++i )
- _events[i].Init();
- }
- /// @brief Pauses the timeline
- public virtual void Pause()
- {
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].HasTriggered && !_events[i].HasFinished )
- _events[i].Pause();
- }
- }
- /// @brief Resumes the timeline
- public virtual void Resume()
- {
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].HasTriggered && !_events[i].HasFinished )
- _events[i].Resume();
- }
- }
- public override void Stop()
- {
- for( int i = _events.Count-1; i >= 0; --i )
- {
- if( _events[i].HasTriggered )
- _events[i].Stop();
- }
- _currentEvent = Sequence.IsPlayingForward ? 0 : _events.Count - 1;
- }
- /// @brief Returns true if the track has no events
- public bool IsEmpty()
- {
- return _events.Count == 0;
- }
- /// @brief Returns to which timeline this track belongs
- public FTimeline Timeline { get { return _timeline; } }
- /// @brief Returns which type of event this track holds
- public Type GetEventType()
- {
- if( _evtType == null )
- {
- _evtType = Type.GetType( _evtTypeStr );
- }
- return _evtType;
- }
- /// @brief Sets the type of event this track holds
- /// @param evtType Has to inherit from FEvent
- private void SetEventType( Type evtType )
- {
- #if NETFX_CORE
- if (!evtType.GetTypeInfo().IsSubclassOf( typeof(FEvent) ) )
- #else
- if (!evtType.IsSubclassOf(typeof(FEvent)))
- #endif
- throw new ArgumentException( evtType.ToString() + " does not inherit from FEvent");
- _evtType = evtType;
- _evtTypeStr = evtType.ToString();
- }
- /// @brief Returns event on position \e index, they are ordered left to right.
- public FEvent GetEvent( int index )
- {
- return _events[index];
- }
- /// @brief Returns events at a specific frame.
- public int GetEventsAt( int t, FEvent[] evtBuffer )
- {
- int index = 0;
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].Start <= t && _events[i].End >= t )
- evtBuffer[index++] = _events[i];
- else if( _events[i].Start > t ) // since they are ordered, no point in continuing
- break;
- }
- return index;
- }
- /// @brief Returns events at a given frame
- /// @param [in] t Frame
- /// @param [out] first First event, if there's 2 events it will be the one ending on that frame
- /// @param [out] second Second event, if there's 2 events it will be the one starting on that frame
- /// @return How many events are at frame \e t
- public int GetEventsAt( int t, out FEvent first, out FEvent second )
- {
- int index = 0;
- first = null;
- second = null;
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].Start <= t && _events[i].End >= t )
- {
- if( index == 0 )
- first = _events[i];
- else
- second = _events[i];
- ++index;
- }
- else if( _events[i].Start > t ) // since they are ordered, no point in continuing
- break;
- }
-
- return index;
- }
- public FEvent GetEventBefore( int t )
- {
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].Start >= t )
- {
- if( i > 0 )
- {
- return _events[i-1];
- }
- return null;
- }
- }
-
- return _events.Count > 0 ? _events[_events.Count-1] : null;
- }
- public FEvent GetEventAfter( int t )
- {
- for( int i = _events.Count-1; i >= 0; --i )
- {
- if( _events[i].End <= t )
- {
- if( i < _events.Count-1 )
- {
- return _events[i+1];
- }
- return null;
- }
- }
- return _events.Count > 0 ? _events[0] : null;
- }
- public bool CanAdd( FEvent evt )
- {
- foreach( FEvent e in _events )
- {
- // abort search, events are ordered!
- if( e.Start > evt.End )
- {
- break;
- }
- if( evt.Collides( e ) )
- {
- return false;
- }
- }
- return true;
- }
- public bool CanAdd( FEvent evt, FrameRange newRange )
- {
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].Start > newRange.End )
- break;
- if( _events[i] == evt )
- continue;
- if( _events[i].FrameRange.Collides( newRange ) )
- return false;
- }
- return true;
- }
- public bool CanAddAt( int t )
- {
- foreach( FEvent e in _events )
- {
- if( e.Start < t + 1 && e.End > t )
- {
- return false;
- }
- }
- return true;
- }
- public bool CanAddAt( int t, out int maxLength )
- {
- maxLength = 0;
- if( t < 0 )
- {
- return false;
- }
- for( int i = 0; i != _events.Count; ++i )
- {
- if( _events[i].Start > t )
- {
- maxLength = _events[i].Start - t;
- return true;
- }
- else if( _events[i].Start <= t && _events[i].End > t )
- {
- return false;
- }
- }
- if( t >= Sequence.Length - 1 )
- {
- return false;
- }
- maxLength = Sequence.Length - t;
- return true;
- }
- public void Add( FEvent evt )
- {
- evt.SetTrack( this );
- for( int i = 0, limit = _events.Count; i != limit; ++i )
- {
- if( _events[i].Start > evt.End )
- {
- _events.Insert(i, evt);
- UpdateEventIds();
- return;
- }
- }
- // didn't find a spot, add at the end
- evt.SetId( _events.Count );
- _events.Add( evt );
- if( !Sequence.IsStopped )
- Init();
- }
- public void Remove( FEvent evt )
- {
- _events.Remove( evt );
- evt.SetTrack( null );
- UpdateEventIds();
- }
- public virtual void UpdateEvents( int frame, float time )
- {
- int limit = _events.Count;
- if( limit == 0 )
- return;
- int increment = 1;
-
- if( !Sequence.IsPlayingForward )
- {
- limit = -1;
- increment = -1;
- }
- for( int i = _currentEvent; i != limit; i += increment )
- {
- if( frame < _events[i].Start )
- {
- if( _events[i].HasTriggered )
- _events[i].Stop();
- if( Sequence.IsPlayingForward )
- break;
- else
- _currentEvent = Mathf.Clamp( i - 1, 0, _events.Count-1 );
- }
- else if( frame >= _events[i].Start && frame <= _events[i].End )
- {
- if( _events[i].HasFinished && Sequence.FrameChanged )
- _events[i].Stop();
- if( !_events[i].HasFinished )
- _events[i].UpdateEvent( frame - _events[i].Start, time-_events[i].StartTime );
- }
- else //if( frame > _events[_currentEvent].End ) // is it finished
- {
- if( !_events[i].HasFinished && (_events[i].HasTriggered || _events[i].TriggerOnSkip) )
- {
- _events[i].UpdateEvent( _events[i].Length, _events[i].LengthTime );
- }
- if( Sequence.IsPlayingForward )
- _currentEvent = Mathf.Clamp( i + 1, 0, _events.Count-1);
- else
- break;
- }
- }
- }
- public virtual void UpdateEventsEditor( int frame, float time )
- {
- _currentEvent = Sequence.IsPlayingForward ? 0 : _events.Count-1;
- UpdateEvents( frame, time );
- }
- private FTrackCache _cache = null;
- /** @brief Returns current Cache. */
- public FTrackCache Cache { get { return _cache; } set { _cache = value; }}
- /** @brief Does it have cache? */
- public bool HasCache { get { return _cache != null; } }
- /** @brief Create Cache, if it needs it. */
- public virtual void CreateCache(){ }
- /** @brief Clear Cache, if it needs it. */
- public virtual void ClearCache(){ }
- /** @brief Does this track have everything it needs to create the cache? */
- public virtual bool CanCreateCache()
- {
- return true;
- }
- public void Rebuild()
- {
- Transform t = transform;
- _events.Clear();
- for( int i = 0; i != t.childCount; ++i )
- {
- FEvent evt = t.GetChild(i).GetComponent<FEvent>();
- if( evt )
- {
- evt.SetTrack( this );
- _events.Add( evt );
- }
- }
- UpdateEventIds();
- }
- public void UpdateEventIds()
- {
- _events.Sort( delegate( FEvent c1, FEvent c2 ) { return c1.FrameRange.Start.CompareTo( c2.FrameRange.Start ); } );
- for(int i = 0, limit = _events.Count; i != limit; ++i )
- {
- _events[i].SetId( i );
- }
- }
- public FrameRange GetValidRange( FEvent evt )
- {
- int index = 0;
- for( ; index < _events.Count; ++index )
- {
- if( _events[index] == evt )
- {
- break;
- }
- }
- FrameRange range = new FrameRange( 0, Sequence.Length );
- if( index > 0 )
- {
- range.Start = _events[index - 1].End;
- }
- if( index < _events.Count - 1 )
- {
- range.End = _events[index + 1].Start;
- }
- if( range.Length > evt.GetMaxLength() )
- range.Length = evt.GetMaxLength();
- return range;
- }
- }
- }
|