/// <summary> /// Executes a callback inside an infinite loop until ttHandler.Break(). /// </summary> private static IEnumerator ExecuteInfiniteLoop(MonoBehaviour instance, string queueName, Action <ttHandler> callback) { // #fix // Inmediate execution breaks the queue order with nested queues yield return(new WaitForEndOfFrame()); ttHandler loopHandler = new ttHandler(); // Run while active while (loopHandler.isActive) { // deltaTime float unityDeltaTime = Time.deltaTime; loopHandler.deltaTime = unityDeltaTime; loopHandler.timeSinceStart += unityDeltaTime; // Pause while (IsPaused(instance, queueName)) { yield return(null); } // Callback execution if (callback != null) { callback(loopHandler); } // Waits all the yields, once if (loopHandler.yieldsToWait != null) { foreach (YieldInstruction yi in loopHandler.yieldsToWait) { yield return(yi); } loopHandler.yieldsToWait.Clear(); } // Executes & waits all IEnumerators, once if (loopHandler.ienumsToWait != null) { foreach (IEnumerator ien in loopHandler.ienumsToWait) { yield return(instance.StartCoroutine(ien)); } loopHandler.ienumsToWait.Clear(); } yield return(null); } }
// THE COROUTINE /// This is the main algorithm. Executes all tasks, one after the /// other, calling their callbacks according to type, time and queue /// config. private IEnumerator ExecuteQueue() { _isPlaying = true; int reverseLastTask = -1; // Important: This value needs to be reset to default on most queue changes _lastPlayExecutedCount = 0; // :D! // 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); 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; // :D? // 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); // Is this more precise that the previous commented code? float time = 0; while (time < delayDuration) { time += Time.deltaTime; yield return(null); } // 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; } // Just at the end of a complete queue execution if (_tasks.Count > 0 && _currentTask >= _tasks.Count) { // Forget current nested queues _waiting.Clear(); } // 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 } } // Done! _isPlaying = false; yield return(null); }
/// <summary> /// Executes a timed callback. /// </summary> private static IEnumerator ExecuteOnce(MonoBehaviour instance, string queueName, float timeToWait, YieldInstruction yieldToWait, Action callback, Action <ttHandler> callbackWithHandler) { // #fix // Inmediate execution breaks the queue order with nested queues if (timeToWait < Time.deltaTime && yieldToWait == null) { yield return(new WaitForEndOfFrame()); } // Pause while (IsPaused(instance, queueName)) { yield return(null); } // Wait for if (timeToWait > 0) { yield return(new WaitForSeconds(timeToWait)); } if (yieldToWait != null) { yield return(yieldToWait); } // Executes the normal callback if (callback != null) { callback(); } // Executes the callback with handler (and waits his yields / ienumerators) if (callbackWithHandler != null) { ttHandler t = new ttHandler(); callbackWithHandler(t); // Waits all the handler yields if (t.yieldsToWait != null) { foreach (YieldInstruction yi in t.yieldsToWait) { yield return(yi); } } // Executes and waits all the handler IEnumerators if (t.ienumsToWait != null) { foreach (IEnumerator ien in t.ienumsToWait) { yield return(instance.StartCoroutine(ien)); } } } yield return(null); }
/// <summary> /// Executes a callback inside a loop for all his duration or until ttHandler.Break(). /// </summary> private static IEnumerator ExecuteLoop(MonoBehaviour instance, string queueName, float duration, Action <ttHandler> callback) { // Only for positive values if (duration <= 0) { yield break; } // #fix // Inmediate execution breaks the queue order with nested queues yield return(new WaitForEndOfFrame()); // Handler data ttHandler loopHandler = new ttHandler(); float tRate = 1 / duration; // Run while active until duration while (loopHandler.isActive && loopHandler.t <= 1) { // deltaTime float unityDeltatime = Time.deltaTime; // Completion % from 0 to 1 loopHandler.t += tRate * unityDeltatime; // Customized delta that represents the loop duration loopHandler.deltaTime = 1 / (duration - loopHandler.timeSinceStart) * unityDeltatime; loopHandler.timeSinceStart += unityDeltatime; // Pause while (IsPaused(instance, queueName)) { yield return(null); } // Callback execution if (callback != null) { callback(loopHandler); } // Waits all the yields, once if (loopHandler.yieldsToWait != null) { foreach (YieldInstruction yi in loopHandler.yieldsToWait) { yield return(yi); } loopHandler.yieldsToWait.Clear(); } // Executes and waits all IEnumerators, once if (loopHandler.ienumsToWait != null) { foreach (IEnumerator ien in loopHandler.ienumsToWait) { yield return(instance.StartCoroutine(ien)); } loopHandler.ienumsToWait.Clear(); } yield return(null); } }