Exemple #1
0
    // ADD

    /// Appends a new ttTask.
    private TeaTime Add(float timeDelay, Func <float> timeDelayByFunc, Action callback, Action <ttHandler> callbackWithHandler)
    {
        // Ignores appends on Immutable mode
        if (!_isImmutable)
        {
            ttTask newTask = new ttTask();
            newTask.time                = timeDelay;
            newTask.timeByFunc          = timeDelayByFunc;
            newTask.callback            = callback;
            newTask.callbackWithHandler = callbackWithHandler;

            _tasks.Add(newTask);
        }

        // Autoplay if not paused or playing
        return(_isPaused || _isPlaying ? this : this.Play());
    }
Exemple #2
0
    // LOOP

    /// Appends a callback loop (if duration is less than 0, the loop runs
    /// infinitely).
    private TeaTime Loop(float duration, Func <float> durationByFunc, Action <ttHandler> callback)
    {
        // Ignores appends on Immutable mode
        if (!_isImmutable)
        {
            ttTask newTask = new ttTask();
            newTask.isLoop              = true;
            newTask.time                = duration;
            newTask.timeByFunc          = durationByFunc;
            newTask.callbackWithHandler = callback;

            _tasks.Add(newTask);
        }

        // Autoplay if not paused or playing
        return(_isPaused || _isPlaying ? this : this.Play());
    }
Exemple #3
0
    /// <summary>
    /// Appends a callback (timed or looped) into a queue.
    /// </summary>
    private static MonoBehaviour ttAdd(this MonoBehaviour instance,
                                       float timeDelay, YieldInstruction yieldDelay,
                                       Action callback, Action <ttHandler> callbackWithHandler,
                                       bool isLoop)
    {
        PrepareCurrentQueueName(instance);
        string queueName = currentQueueName[instance];


        // Ignore locked
        if (IsLockedOrUnlockEmpty(instance, queueName))
        {
            return(instance);
        }


        // Adds a new task in the main queue
        ttTask currentTask = new ttTask(instance, queueName,
                                        timeDelay, yieldDelay,
                                        callback, callbackWithHandler,
                                        isLoop);

        mainQueue[instance][queueName].Add(currentTask);


        // Mirrors the main queue in blueprints
        blueprints[instance][queueName].Add(currentTask);


        // Execute when isn't paused
        if (!IsPaused(instance, queueName))
        {
            instance.StartCoroutine(ExecuteQueue(instance, queueName));
        }


        return(instance);
    }
Exemple #4
0
    // 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);
    }