| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836 |
- using UnityEngine;
- using UnityEngine.Events;
- using System.Collections;
- using System.Collections.Generic;
- /**
- * @brief Flux is top namespace for everything pertaining to the runtime.
- */
- namespace Flux
- {
- public enum ActionOnStart
- {
- None = 0,
- Initialize,
- Play
- }
- /**
- * @brief FSequence is the main runtime class. It holds all the timelines and controls their behaviour.
- * @sa FTimeline, FTrack, FEvent
- */
- public class FSequence : FObject
- {
- public const int DEFAULT_FRAMES_PER_SECOND = 60;
- public const int DEFAULT_LENGTH = 10;
- public const float DEFAULT_SPEED = 1f;
- public static FSequence CreateSequence()
- {
- return CreateSequence( new GameObject("FSequence") );
- }
- public static FSequence CreateSequence( GameObject gameObject )
- {
- FSequence sequence = gameObject.AddComponent<FSequence>();
- sequence._content = new GameObject("SequenceContent").transform;
- sequence._content.hideFlags |= HideFlags.HideInHierarchy;
- sequence._content.parent = sequence.transform;
- sequence.Add( FContainer.Create(FContainer.DEFAULT_COLOR) );
- sequence.Version = FUtility.FLUX_VERSION;
- return sequence;
- }
- [SerializeField]
- [HideInInspector]
- private GameObject _CasterActor = null;
- public GameObject CasterActor
- {
- get { return _CasterActor; }
- set
- {
- if(_CasterActor!=null)
- {
- _CasterActor = value;
- ResetDefaultVal();
- }
- }
- }
- [SerializeField]
- [HideInInspector]
- private GameObject _TargetActor = null;
- public GameObject TargetActor
- {
- get { return _TargetActor; }
- set {
- if(_TargetActor!=value)
- {
- _TargetActor = value;
- ResetDefaultVal();
- }
- }
- }
- [SerializeField]
- private GameObject _CameraGo = null;
- public GameObject CameraGo
- {
- get { return _CameraGo; }
- set { _CameraGo = value; }
- }
- [SerializeField]
- private Transform _content = null;
- /// @brief Child Transform (hidden by default) that holds the containers.
- public Transform Content { get { return _content; } set { _content = value; _content.parent = transform; } }
- [SerializeField]
- private List<FContainer> _containers = new List<FContainer>();
- /// @brief Containers inside the sequence.
- public List<FContainer> Containers { get { return _containers; } }
- [SerializeField]
- [HideInInspector]
- private int _version = 0;
- public int Version { get { return _version; } set { _version = value; } }
- [SerializeField]
- [Tooltip("What should be the default action when Start() gets called?\n\tNone\n\tInitialize\n\tPlay")]
- private ActionOnStart _actionOnStart = ActionOnStart.None;
- /// @brief What should be the default action when Start() gets called?
- public ActionOnStart ActionOnStart { get{ return _actionOnStart; } set { _actionOnStart = value; } }
- [SerializeField]
- private bool _loop = false;
- /// @brief Does the sequence loop when it reaches the end?
- public bool Loop { get { return _loop; } set { _loop = value; } }
- [SerializeField]
- private float _defaultSpeed = DEFAULT_SPEED;
- /// @brief Speed that is used when sequence is loaded. When you want to change runtime see, use Speed instead
- public float DefaultSpeed { get { return _defaultSpeed; } set { _defaultSpeed = value; } }
- private float _speed = DEFAULT_SPEED;
- /// @brief Current speed, used to control the speed of the sequence. If negative, sequence will play backwards.
- public float Speed {
- get{ return _speed; }
- set{
- bool wasPlayingForward = _isPlayingForward;
- _speed = value;
- _isPlayingForward = Speed * Time.timeScale >= 0;
- // if we change the speed to playing back while it is playing already we need
- // to create the track caches to handle going backwards
- if( (wasPlayingForward != _isPlayingForward) && Application.isPlaying && IsInit )
- CreateTrackCaches();
- }
- }
- /// @brief Should it update on FixedUpdate? If false, it will update on Update.
- [SerializeField]
- private AnimatorUpdateMode _updateMode = AnimatorUpdateMode.Normal;
- public AnimatorUpdateMode UpdateMode { get { return _updateMode; } set { _updateMode = value; } }
- /// @brief The length of this sequence in frames.
- [SerializeField]
- private int _length = DEFAULT_LENGTH * DEFAULT_FRAMES_PER_SECOND;
- /// @brief Length of this sequence in frames.
- public int Length { get { return _length; } set { _length = value; } }
- /// @brief Returns the length of this sequence in seconds.
- /// @Warning This value isn't cached internally, so avoid calling it all the time.
- public float LengthTime { get { return (float)_length * _inverseFrameRate; } }
- [SerializeField]
- [HideInInspector]
- private SequenceFinishedEvent _onFinishedCallback = new SequenceFinishedEvent();
- /// @brief Callback when sequence reaches last frame (or frame 0 when moving backwards)
- public SequenceFinishedEvent OnFinishedCallback { get { return _onFinishedCallback; } }
- // private FTimeline _globalTimeline = null;
- // /// @brief Global Timeline. It is always visible, doesn't get processed at runtime, and used for things like comment track.
- // public FTimeline GlobalTimeline { get { return _globalTimeline; } }
- [SerializeField]
- [HideInInspector]
- private int _frameRate = DEFAULT_FRAMES_PER_SECOND; // frame rate
- /** @brief Frame Rate of this sequence.
- * @Warning Although we allow you to change this value at runtime, you should be careful in how you use it.
- * Changing this value \b will not \b rescale the sequence. Rescaling the sequence should only be done in editor,
- * not at runtime.
- * @sa CSequenceInspector.Rescale(CSequence, int)
- * @sa InverseFrameRate
- */
- public int FrameRate { get { return _frameRate; } set { _frameRate = value; _inverseFrameRate = 1f / _frameRate; } }
- [SerializeField]
- [HideInInspector]
- private float _inverseFrameRate = 1f / DEFAULT_FRAMES_PER_SECOND;
- /// @brief Returns 1 / FrameRate. This value is cached and set automatically when FrameRate is called.
- /// @sa FrameRate
- public float InverseFrameRate { get { return _inverseFrameRate; } }
- // has it been initialized?
- private bool _isInit = false;
- /// @brief Is the sequence initialized?
- public bool IsInit { get { return _isInit; } }
- // Is the sequence playing?
- private bool _isPlaying = false;
- /// @brief Is the sequence playing?
- public bool IsPlaying { get { return _isPlaying; } }
- // Is the sequence playing forward?
- private bool _isPlayingForward = true;
- /// @brief Is the sequence moving forward?
- public bool IsPlayingForward { get { return _isPlayingForward; } }
- // time we last updated
- private float _lastUpdateTime = 0;
- public override Transform Owner {
- get {
- return transform;
- }
- }
- public override FSequence Sequence {
- get {
- return this;
- }
- }
- public void Add( FContainer container )
- {
- int id = _containers.Count;
- _containers.Add( container );
- container.SetId( id );
- container.SetSequence( this );
- }
- public void Remove( FContainer container )
- {
- if( _containers.Remove( container ) )
- {
- container.SetSequence( null );
- UpdateContainerIds();
- }
- }
- // Current frame, i.e. (int)(_currentTime * frameRate)
- private int _currentFrame = -1;
- // Last frame, to determine if the frame has advanced or not
- private int _lastFrame = -1;
- // What's the current time
- private float _currentTime = -1;
- /** @brief Sets the current time, to be used when in editor mode, _not_ for runtime.
- * @param time Time.
- * @sa SetCurrentTime
- */
- public void SetCurrentTimeEditor( float time )
- {
- if( time != _currentTime && _currentFrame != -1 )
- Speed = time > _currentTime ? Mathf.Abs(Speed) : -Mathf.Abs(Speed);
- CurrentTime = Mathf.Clamp( time, 0, LengthTime );
- for( int i = 0; i != _containers.Count; ++i )
- {
- if( !_containers[i].enabled ) continue;
- _containers[i].UpdateTimelinesEditor( _currentFrame, _currentTime );
- }
- }
- /**
- * @brief Sets the current time manually, e.g. if you want to jump to a specific point of the
- * sequence.
- * @param time Time.
- * @sa SetCurrentFrame, SetCurrentTimeEditor
- */
- public void SetCurrentTime( float time )
- {
- if( !_isInit )
- Init();
-
- // if setting the time we're on, or we just started playing, ignore this
- if( time != _currentTime && _currentFrame != -1 )
- {
- // if we're changing time in a direction different from the one we're going,
- // we need to clear the tracks in order to be in the proper state when we move to
- // a certain time
- if( ! (IsPlayingForward && time > _currentTime) )
- {
- for( int i = 0; i != _containers.Count; ++i )
- _containers[i].Stop();
- }
- }
- SetCurrentTimeInternal( time );
- }
- /** @brief Sets the current time based on the frame, but just calculates it internally for you.
- * @param frame Frame.
- * @sa SetCurrentTime
- */
- public void SetCurrentFrame( int frame )
- {
- SetCurrentTime( frame * InverseFrameRate );
- }
- /// @brief Sets the current frame based on the time passed.
- /// @param time Time in seconds, this will set current frame with time x FrameRate.
- protected void SetCurrentTimeInternal( float time )
- {
- CurrentTime = Mathf.Clamp( time, 0, LengthTime );
- for( int i = 0; i != _containers.Count; ++i )
- {
- if( !_containers[i].enabled ) continue;
- _containers[i].UpdateTimelines( _currentFrame, _currentTime );
- }
- }
- /// @brief Returns the current frame.
- /// @sa SetCurrentFrame, GetCurrentFrame
- public int CurrentFrame {
- get {
- return _currentFrame;
- }
- private set {
- _lastFrame = value < 0 ? -1 : _currentFrame;
- _currentFrame = value;
- }
- }
- /** @brief Returns current time. */
- public float CurrentTime {
- get {
- return _currentTime;
- }
- private set {
- _currentTime = value;
- if( _currentTime < 0 )
- CurrentFrame = -1;
- else
- {
- float epsilon = 0.001f;
- CurrentFrame = IsPlayingForward ? Mathf.FloorToInt(_currentTime * _frameRate + epsilon) : Mathf.CeilToInt(_currentTime*_frameRate - epsilon);
- }
- }
- }
- public bool FrameChanged { get { return _lastFrame != _currentFrame; } }
- /// @brief Initializes the sequence.
- /// This is called at the start of the sequence, it is meant for the
- /// user to setup all the cached variables.
- /// @note If you want to avoid frame drops, call this function before
- /// calling Play.
- public override void Init()
- {
- #if FLUX_DEBUG
- Debug.Log("Init");
- #endif
- #if FLUX_PROFILE
- Profiler.BeginSample( "FSequence.Init()" );
- #endif
- _isInit = true; // set init first so that cache doesn't go into infinite loop
- for( int i = 0; i != _containers.Count; ++i )
- _containers[i].Init();
- // build caches for tracks that require it at runtime
- CreateTrackCaches();
- _isInit = true; // force again init since create caches can clear it
- #if FLUX_PROFILE
- Profiler.EndSample();
- #endif
- }
- public void CreateTrackCaches()
- {
- for( int i = 0; i != _containers.Count; ++i )
- {
- List<FTimeline> timelines = _containers[i].Timelines;
- for( int j = 0; j != timelines.Count; ++j )
- {
- List<FTrack> tracks = timelines[j].Tracks;
- foreach( FTrack track in tracks )
- {
- #if UNITY_EDITOR
- if( ((!Application.isPlaying && track.RequiresEditorCache) || (IsPlayingForward && track.RequiresForwardCache) || (!IsPlayingForward && track.RequiresBackwardsCache)) && !track.HasCache )
- track.CreateCache();
- #else
- if( ((IsPlayingForward && track.RequiresForwardCache) || (!IsPlayingForward && track.RequiresBackwardsCache)) && !track.HasCache )
- track.CreateCache();
- #endif
- }
- }
- }
- }
- public void DestroyTrackCaches()
- {
- foreach( FContainer container in Containers )
- {
- foreach( FTimeline timeline in container.Timelines )
- {
- foreach( FTrack track in timeline.Tracks )
- {
- if( track.HasCache )
- track.ClearCache();
- }
- }
- }
- }
- /// @override Starts playing on a specific frame.
- public void Play( int startFrame )
- {
- Play( startFrame * _inverseFrameRate );
- }
- /// @brief Starts playing at time.
- /// @param startTime What time to start playing from.
- /// @sa Init
- public void Play( float startTime )
- {
- if( _isPlaying )
- return;
-
- _isPlayingForward = Speed * Time.timeScale >= 0;
-
- if( !_isInit )
- Init();
-
- if( !IsStopped )
- Resume();
-
- _isPlaying = true;
-
- switch( _updateMode )
- {
- case AnimatorUpdateMode.Normal:
- _lastUpdateTime = Time.time;
- break;
- case AnimatorUpdateMode.AnimatePhysics:
- _lastUpdateTime = Time.fixedTime;
- break;
- case AnimatorUpdateMode.UnscaledTime:
- _lastUpdateTime = Time.unscaledTime;
- break;
- default:
- Debug.LogError("Unsupported Update Mode");
- _lastUpdateTime = Time.time;
- break;
- }
-
- SetCurrentTimeInternal( startTime );
- }
- /// @brief Starts playing from either the start or the end, depending on which
- /// direction it is playing.
- /// @sa Init, Stop, Pause
- public void Play()
- {
- if( IsPlayingForward )
- Play( 0f );
- else
- Play( LengthTime );
- }
- /// @brief Stops sequence.
- public override void Stop()
- {
- Stop( false );
- }
- /** @brief Stops sequence.
- * @param reset If true, it clears Init, i.e. it will force the Init phase to happen again.
- */
- public void Stop( bool reset )
- {
- if( reset )
- _isInit = false;
- if ( IsStopped && !reset )
- return;
- #if FLUX_DEBUG
- Debug.Log ("Stop");
- #endif
- _isPlaying = false;
- _isPlayingForward = Speed*Time.timeScale >= 0;
- for( int i = 0; i != _containers.Count; ++i )
- _containers[i].Stop();
- CurrentTime = -1;
- _lastUpdateTime = 0;
- }
- /**
- * @brief Pauses sequence.
- * @sa FEvent.OnPause, FEvent.OnResume
- */
- public void Pause()
- {
- if( !_isPlaying )
- return;
- _isPlaying = false;
- for( int i = 0; i != _containers.Count; ++i )
- _containers[i].Pause();
- }
- /**
- * @brief Resumes a sequence that is paused.
- * Doesn't work if the sequence is stopped.
- * @sa Play, Stop, Pause
- */
- public void Resume()
- {
- if( _isPlaying )
- return;
- _isPlaying = true;
- for( int i = 0; i !=_containers.Count; ++i )
- _containers[i].Resume();
- switch( _updateMode )
- {
- case AnimatorUpdateMode.Normal:
- _lastUpdateTime = Time.time;
- break;
- case AnimatorUpdateMode.AnimatePhysics:
- _lastUpdateTime = Time.fixedTime;
- break;
- case AnimatorUpdateMode.UnscaledTime:
- _lastUpdateTime = Time.unscaledTime;
- break;
- default:
- Debug.LogError("Unsupported Update Mode");
- _lastUpdateTime = Time.time;
- break;
- }
- }
- /// @brief Is the sequence paused?
- public bool IsPaused { get { return !_isPlaying && _currentFrame >= 0; } }
- /// @brief Is the sequence stopped?
- public bool IsStopped { get { return _currentFrame < 0; } }
- /// @brief Is the sequence finished? Does not finish when it loops.
- public bool IsFinished { get { return IsPaused && ((IsPlayingForward && _currentTime == LengthTime) || (!IsPlayingForward && _currentTime == 0)); } }
- /// @brief Does the sequence have no events?
- public bool IsEmpty()
- {
- foreach( FContainer container in _containers )
- {
- if( !container.IsEmpty() )
- return false;
- }
- return true;
- }
- /// @brief Determines wether it has any timelines.
- public bool HasTimelines()
- {
- foreach( FContainer container in _containers )
- {
- if( container.Timelines.Count > 0 )
- return true;
- }
- return false;
- }
- protected virtual void Awake()
- {
- Speed = DefaultSpeed;
- _isPlayingForward = Speed * Time.timeScale >= 0;
- }
- protected virtual void Start()
- {
- switch( _actionOnStart )
- {
- case ActionOnStart.None:
- // do nothing
- break;
- case ActionOnStart.Initialize:
- Init();
- break;
- case ActionOnStart.Play:
- Play();
- break;
- }
- }
- // Updates the sequence when update mode is NOT AnimatePhysics
- protected virtual void Update()
- {
- if( _updateMode == AnimatorUpdateMode.AnimatePhysics || !_isPlaying )
- {
- return;
- }
- InternalUpdate( _updateMode == AnimatorUpdateMode.Normal ? Time.time : Time.unscaledTime );
- }
- // Updates the sequence when update mode is AnimatePhysics
- protected virtual void FixedUpdate()
- {
- if( _updateMode != AnimatorUpdateMode.AnimatePhysics || !_isPlaying )
- {
- return;
- }
- InternalUpdate( Time.fixedTime );
- }
- protected virtual void InternalUpdate( float time )
- {
- float delta = time - _lastUpdateTime;
- if( delta != 0 )
- {
- SetCurrentTimeInternal( _currentTime + delta * Speed );
- if( _isPlayingForward )
- {
- if( _currentTime == LengthTime )
- {
- OnFinishedCallback.Invoke( this );
- if( _loop )
- {
- Stop();
- Play();
- }
- else
- {
- Pause();
- }
- }
- }
- else
- {
- if( _currentTime == 0 )
- {
- OnFinishedCallback.Invoke( this );
- if( _loop )
- {
- Stop();
- Play(); // @TODO Play backwards
- }
- else
- {
- Pause();
- }
- }
- }
- _lastUpdateTime = time;
- }
- }
- public void Rebuild()
- {
- #if FLUX_DEBUG
- Debug.Log("Rebuilding");
- #endif
- _containers.Clear();
- Transform t = Content;
- for( int i = 0; i != t.childCount; ++i )
- {
- FContainer container = t.GetChild( i ).GetComponent<FContainer>();
- if( container != null )
- {
- _containers.Add( container );
- container.SetSequence( this );
- container.Rebuild();
- }
- }
- UpdateContainerIds();
- }
- private void UpdateContainerIds()
- {
- for( int i = 0; i != _containers.Count; ++i )
- {
- _containers[i].SetId( i );
- }
- }
- public void ReplaceOwner( Transform oldOwner, Transform newOwner )
- {
- foreach( FContainer container in _containers )
- {
- foreach( FTimeline timeline in container.Timelines )
- {
- if( timeline.Owner == oldOwner )
- timeline.SetOwner( newOwner );
- }
- }
- }
- public void ReplaceOwner( string timelineName, Transform newOwner )
- {
- foreach( FContainer container in _containers )
- {
- foreach( FTimeline timeline in container.Timelines )
- {
- if( timeline.gameObject.name == timelineName )
- timeline.SetOwner( newOwner );
- }
- }
- }
- public void ReplaceOwnerByPath( string ownerPath, Transform newOwner )
- {
- foreach( FContainer container in _containers )
- {
- foreach( FTimeline timeline in container.Timelines )
- {
- if( timeline.OwnerPath == ownerPath )
- timeline.SetOwner( newOwner );
- }
- }
- }
- public void ReplaceOwner( params KeyValuePair<Transform, Transform>[] replacements )
- {
- foreach( FContainer container in _containers )
- {
- foreach( FTimeline timeline in container.Timelines )
- {
- foreach( KeyValuePair<Transform, Transform> replacement in replacements )
- {
- if( timeline.Owner == replacement.Key )
- {
- timeline.SetOwner( replacement.Value );
- break;
- }
- }
- }
- }
- }
- #if UNITY_EDITOR
- public void SaveToXml()
- {
- foreach (FContainer container in _containers)
- {
- foreach(FTimeline timeline in container.Timelines )
- {
- timeline.SaveToXml();
- }
- }
- }
- public void LoadFromXml()
- {
- }
- #endif
- public void ResetDefaultVal()
- {
- if(Containers!=null)
- {
- for(int idx =0; idx < Containers.Count;idx++)
- {
- FContainer c = Containers[idx];
- for (int jdx = 0; jdx < c.Timelines.Count;jdx++)
- {
- FTimeline tline = c.Timelines[jdx];
- for(int kdx = 0; kdx < tline.Tracks.Count;kdx++ )
- {
- FTrack track = tline.Tracks[kdx];
- for(int edx = 0; edx < track.Events.Count;edx++)
- {
- FEvent evt = track.Events[edx];
- evt.SetDefaultValues();
- }
- }
- }
- }
- }
- }
- #if FLUX_TRIAL
- private Rect _watermarkLabelRect = new Rect(0,0,0,0);
- private GUIStyle _watermarkLabelStyle;
- private float _watermarkEndTime;
- private float _watermarkAlpha;
- private void OnGUI()
- {
- if( !IsPlaying )
- return;
- float watermarkDuration = 3f;
- GUIContent watermark = new GUIContent("..::FLUX TRIAL::..");
- if( _watermarkLabelRect.width == 0 )
- {
- _watermarkLabelStyle = new GUIStyle(GUI.skin.label);
- _watermarkLabelStyle.fontSize = 24;
- Vector2 size = _watermarkLabelStyle.CalcSize( watermark );
- _watermarkLabelRect.x = Random.Range(0, Screen.width-size.x);
- _watermarkLabelRect.y = Random.Range(0, 2);
- if( _watermarkLabelRect.y == 1 )
- _watermarkLabelRect.y = Screen.height-size.y;
- _watermarkLabelRect.width = size.x;
- _watermarkLabelRect.height = size.y;
- _watermarkEndTime = Time.time + watermarkDuration;
- _watermarkAlpha = 1.6f;
- }
- GUI.color = new Color(1f, 1f, 1f, _watermarkAlpha + 0.4f );
- GUI.Label( _watermarkLabelRect, watermark, _watermarkLabelStyle );
- if( Time.time < _watermarkEndTime )
- {
- _watermarkAlpha -= Time.deltaTime / watermarkDuration;
- if( _watermarkAlpha < 0 )
- _watermarkAlpha = 0;
- }
- }
- #endif
- }
-
- [System.Serializable]
- public class SequenceFinishedEvent : UnityEvent<FSequence>
- {
- }
- }
|