Example #1
0
        // @
        // THE COROUTINE


        /// <summary>
        /// This is the main algorithm. Executes all tasks, one after the
        /// other, calling their callbacks according to type, time and queue
        /// config.
        /// </summary>
        private IEnumerator ExecuteQueue()
        {
            _isPlaying = true;


            int reverseLastTask = -1;             // Important: This value needs to be reset to default on most queue changes

            _lastPlayExecutedCount = 0;

            while (_currentTask < _tasks.Count)
            {
                // Current task to be executed
                int taskId = _currentTask;
                if (_isReversed)
                {
                    taskId = _tasks.Count - 1 - _currentTask;
                }
                ttTask currentTask = _tasks[taskId];


                // Next task (or previous if the queue is backward)
                _currentTask++;

                // Avoid executing a task twice when reversed and the queue
                // hasn't reached the end
                if (taskId == reverseLastTask)
                {
                    continue;
                }
                reverseLastTask = taskId;


                // Let's wait
                // 1 For secuencial Adds or Loops before their first execution
                // 2 Maybe a callback is trying to modify his own queue
                yield return(ttYield.EndOfFrame);


                // It's a loop
                if (currentTask.isLoop)
                {
                    // Holds the duration
                    float loopDuration = currentTask.time;

                    // Func<float> added
                    if (currentTask.timeByFunc != null)
                    {
                        loopDuration += currentTask.timeByFunc();
                    }

                    // Nothing to do, skip
                    if (loopDuration == 0)
                    {
                        continue;
                    }


                    // Loops will always need a handler
                    ttHandler loopHandler = new ttHandler();
                    loopHandler.self       = this;
                    loopHandler.isLooping  = true;
                    loopHandler.isReversed = _isReversed;


                    // Negative time means the loop is infinite
                    bool isInfinite = loopDuration < 0;

                    // T quotient
                    float tRate = isInfinite ? 0 : 1 / loopDuration;

                    // Progresion depends on current direction
                    if (loopHandler.isReversed)
                    {
                        loopHandler.t = 1f;
                        tRate         = -tRate;
                    }

                    // While looping and, until time or infinite
                    while (loopHandler.isLooping && (loopHandler.isReversed ? loopHandler.t >= 0 : loopHandler.t <= 1))
                    {
                        // Check for queue reversal
                        if (_isReversed != loopHandler.isReversed)
                        {
                            tRate = -tRate;
                            loopHandler.isReversed = _isReversed;
                        }


                        float unityDeltaTime = Time.deltaTime;

                        // Completion% from 0 to 1
                        if (!isInfinite)
                        {
                            loopHandler.t += tRate * unityDeltaTime;
                        }

                        // On finite loops this .deltaTime is sincronized with
                        // the exact loop duration
                        loopHandler.deltaTime =
                            isInfinite
                                                        ? unityDeltaTime
                                                        : 1 / (loopDuration - loopHandler.timeSinceStart) * unityDeltaTime;

                        // .deltaTime is also reversed
                        if (loopHandler.isReversed)
                        {
                            loopHandler.deltaTime = -loopHandler.deltaTime;
                        }

                        // A classic
                        loopHandler.timeSinceStart += unityDeltaTime;


                        // Pause?
                        while (_isPaused)
                        {
                            yield return(null);
                        }


                        // Loops will always have a callback with a handler
                        currentTask.callbackWithHandler(loopHandler);


                        // Handler .WaitFor(
                        if (loopHandler.yieldsToWait != null)
                        {
                            for (int i = 0, len = loopHandler.yieldsToWait.Count; i < len; i++)
                            {
                                yield return(loopHandler.yieldsToWait[i]);
                            }

                            loopHandler.yieldsToWait.Clear();
                        }


                        // Minimum sane delay
                        if (loopHandler.yieldsToWait == null)
                        {
                            yield return(null);
                        }
                    }


                    // Executed +1
                    _executedCount         += 1;
                    _lastPlayExecutedCount += 1;
                }
                // It's a timed callback
                else
                {
                    // Holds the delay
                    float delayDuration = currentTask.time;

                    // Func<float> added
                    if (currentTask.timeByFunc != null)
                    {
                        delayDuration += currentTask.timeByFunc();
                    }

                    // Time delay
                    if (delayDuration > 0)
                    {
                        yield return(ttYield.Seconds(delayDuration));
                    }


                    // Pause?
                    while (_isPaused)
                    {
                        yield return(null);
                    }


                    // Normal callback
                    if (currentTask.callback != null)
                    {
                        currentTask.callback();
                    }


                    // Callback with handler
                    if (currentTask.callbackWithHandler != null)
                    {
                        ttHandler handler = new ttHandler();
                        handler.self = this;

                        handler.t = 1;
                        handler.timeSinceStart = delayDuration;
                        handler.deltaTime      = Time.deltaTime;

                        currentTask.callbackWithHandler(handler);


                        // Handler WaitFor
                        if (handler.yieldsToWait != null)
                        {
                            for (int i = 0, len = handler.yieldsToWait.Count; i < len; i++)
                            {
                                yield return(handler.yieldsToWait[i]);
                            }

                            handler.yieldsToWait.Clear();
                        }


                        // Minimum sane delay
                        if (delayDuration <= 0 && handler.yieldsToWait == null)
                        {
                            yield return(null);
                        }
                    }
                    else if (delayDuration <= 0)
                    {
                        yield return(null);
                    }


                    // Executed +1
                    _executedCount         += 1;
                    _lastPlayExecutedCount += 1;
                }


                // Consume mode removes the task after execution #todo Need to
                // be tested with .Reverse() stuff
                if (_isConsuming)
                {
                    _currentTask -= 1;
                    _tasks.Remove(currentTask);

                    reverseLastTask = -1;                     // To default
                }


                // On Yoyo mode the queue is reversed at the end, only once per
                // play without Repeat mode
                if (_isYoyo && _currentTask >= _tasks.Count && (_lastPlayExecutedCount <= _tasks.Count || _isRepeating))
                {
                    this.Reverse();

                    reverseLastTask = -1;                     // To default
                }


                // Repeats on Repeat mode
                if (_isRepeating && _tasks.Count > 0 && _currentTask >= _tasks.Count)
                {
                    _currentTask = 0;

                    reverseLastTask = -1;                     // To default
                }


                // Just at the end of a complete queue execution
                if (_tasks.Count > 0 && _currentTask >= _tasks.Count)
                {
                    // A new cycle begins
                    _waiting.Clear();
                }
            }


            // Done!
            _isPlaying = false;


            yield return(null);
        }
Example #2
0
		// ^
		// THE COROUTINE


		/// <summary>
		/// This is the main algorithm. Executes all tasks, one after the
		/// other, calling their callbacks according to type, time and queue
		/// config.
		/// </summary>
		IEnumerator ExecuteQueue()
		{
			_isPlaying = true;


			while (_currentTask < _tasks.Count)
			{
				// Current
				ttTask currentTask = _tasks[_currentTask];

				// Next
				_currentTask += 1;


				// Let's wait
				// 1 For secuencial Adds or Loops before their first execution
				// 2 Maybe a callback is trying to modify his own queue
				yield return new WaitForEndOfFrame();


				// It's a loop
				if (currentTask.isLoop)
				{
					// Nothing to do, skip
					if (currentTask.time == 0)
						continue;


					// Loops always need a handler
					ttHandler loopHandler = new ttHandler();
					loopHandler.self = this;

					// Negative time means the loop is infinite
					bool isInfinite = currentTask.time < 0;

					// T quotient
					float tRate = isInfinite ? 0 : 1 / currentTask.time;

					// While active and, until time or infinite
					while (loopHandler.isActive && loopHandler.t <= 1)
					{
						float unityDeltaTime = Time.deltaTime;

						// Completion % from 0 to 1
						if (!isInfinite)
							loopHandler.t += tRate * unityDeltaTime;

						// On finite loops this .deltaTime is sincronized with
						// the exact loop duration
						loopHandler.deltaTime =
						    isInfinite
						    ? unityDeltaTime
						    : 1 / (currentTask.time - loopHandler.timeSinceStart) * unityDeltaTime;

						loopHandler.timeSinceStart += unityDeltaTime;


						// Pause?
						while (_isPaused)
							yield return null;


						// Loops always have a callback with a handler
						currentTask.callbackWithHandler(loopHandler);


						// Handler .WaitFor(
						if (loopHandler.yieldsToWait != null)
						{
							foreach (YieldInstruction yi in loopHandler.yieldsToWait)
								yield return yi;

							loopHandler.yieldsToWait.Clear();
						}


						// Minimum sane delay
						if (loopHandler.yieldsToWait == null)
							yield return null;
					}
				}
				// It's a timed callback
				else
				{
					// Time delay
					if (currentTask.time > 0)
						yield return new WaitForSeconds(currentTask.time);


					// Yield delay
					if (currentTask.yieldInstruction != null)
						yield return currentTask.yieldInstruction;


					// Pause?
					while (_isPaused)
						yield return null;


					// Normal callback
					if (currentTask.callback != null)
						currentTask.callback();


					// Callback with handler
					ttHandler handler = new ttHandler();
					handler.self = this;

					if (currentTask.callbackWithHandler != null)
					{
						handler.isActive = true;
						handler.t = 1;
						handler.timeSinceStart = currentTask.time;
						handler.deltaTime = Time.deltaTime;

						currentTask.callbackWithHandler(handler);


						// Handler WaitFor
						if (handler.yieldsToWait != null)
						{
							foreach (YieldInstruction yi in handler.yieldsToWait)
								yield return yi;

							handler.yieldsToWait.Clear();
						}
					}


					// Minimum sane delay
					if (currentTask.time <= 0 && handler.yieldsToWait == null)
						yield return null;
				}


				// Consume mode removes the task after execution
				if (_isConsuming)
				{
					_currentTask -= 1;
					_tasks.Remove(currentTask);
				}
			}


			// Repeats on Repeat mode (if needed)
			if (_isRepeating && _tasks.Count > 0)
			{
				_currentTask = 0;
				_currentCoroutine = _instance.StartCoroutine(ExecuteQueue());
			}
			// Done!
			else
			{
				_isPlaying = false;
			}


			yield return null;
		}