dotween icon indicating copy to clipboard operation
dotween copied to clipboard

Append to Already Playing Sequence

Open ceyhuntasci opened this issue 8 years ago • 6 comments

My animation is basicly shows the valid words user found in order.

My method does this:

    if (showWordsSequence.IsPlaying())
    {
        showWordsSequence.Append(group.transform.DOScale(1f, 0.6f));
        showWordsSequence.AppendInterval(0.2f);
        showWordsSequence.Append(group.transform.DOScale(0f, 0.6f));
        showWordsSequence.Append(DOVirtual.DelayedCall(0.2f,() => Destroy(group.gameObject)));

    }
    else
    {
        showWordsSequence = DOTween.Sequence();
        showWordsSequence.Append(group.transform.DOScale(1f, 0.6f));
        showWordsSequence.AppendInterval(0.2f);
        showWordsSequence.Append(group.transform.DOScale(0f, 0.6f));
        showWordsSequence.Append(DOVirtual.DelayedCall(0.2f, () => Destroy(group.gameObject)));
    }

showWordsSequence is a global Sequence variable. When I call this method 3 times in a for loop (in the same frame) it works. But, when sequence starts playing and after 1-2 seconds, i call this method again it does not append the animation. Is there any workaround on this?

ceyhuntasci avatar May 09 '17 15:05 ceyhuntasci

Taken from documentation: http://dotween.demigiant.com/documentation.php

  1. About appending sequences: Note that all these methods need to be applied before the Sequence starts (usually the next frame after you create it, unless it's paused), or they won't have any effect.
  2. About virtual methods (I'm impressed that these work): NOTE: virtual methods can't be placed inside Sequences.

Sadly, the only workaround I know is to create whole sequence beforehand. Other idea is to create second, paused, sequence, append to it and have OnComplete callback starting playback of the new one (if it ain't empty).

Malhavok avatar May 10 '17 08:05 Malhavok

Thanks for your reply!

Wish we could just append to ongoing sequences ^^ I had seen the thing about virtual methods but it always works for me i don't know why.

ceyhuntasci avatar May 10 '17 11:05 ceyhuntasci

I might actually rethink about appending to ongoing Sequences, but will take me a while.

Virtual methods do return a Tween object, so in theory they "can" be added to Sequences. But since they're somehow different, I don't recommend doing that. In short, I'm not taking any responsibility for virtual methods inside Sequences :D

Demigiant avatar May 12 '17 08:05 Demigiant

That would be so great actually.

Yes, you are right. I've rewritten the virtual methods, they are acting kinda funny. Thou shalt not trust virtual methods!!!

ceyhuntasci avatar May 12 '17 09:05 ceyhuntasci

Hi. In case anyone else is googling it in 2019. This is the best workaround for this situation.

//'Global' queue for animations. First one ( .Peek() ) is playing, others are waiting in queue
    public Queue<Sequence> AnimationQueue = new Queue<Sequence>();

    //Entry point
    public void PlayQueuedAnimation()
    {
        //Create paused sequence 
        var seq = DG.Tweening.DOTween.Sequence();
        seq.Pause();

        //Append everything you want
        seq.Append(targetTransform.DOLocalMoveX(5f, 1f));
        //...

        //Add to queue
        AnimationQueue.Enqueue(seq);

        //Check if this animation is first in queue
        if (AnimationQueue.Count == 1)
        {
            AnimationQueue.Peek().Play();
        }

        //Set callback 
        seq.OnComplete(OnComplete);
    }

    //Callback
    private void OnComplete()
    {
        //remove animation that was completed
        AnimationQueue.Dequeue();

        //if there's animations in queue left
        if (AnimationQueue.Count > 0)
        {
            //play next
            AnimationQueue.Peek().Play();
        }
    }

EvgenL avatar Jan 23 '19 13:01 EvgenL

For anyone interested in enqueuing tweens without creating a sequence and without keeping a reference to the tween, possibly after the tween has started, I created a simple extension method:

namespace DG.Tweening
{
    public static class DOTweenQueue
    {
        /// <summary>
        /// Enqueues a Tween to be played when the last enqueued Tween (or the current Tween) is completed.
        /// Starts immediately if no Tween is active. 
        /// </summary>
        /// <remarks>
        /// It probably doesn't work when creating Tweens the generic way;
        /// It probably doesn't work with sequences;
        /// It may have performance implications: uses Linq, creates a List by calling TweensByTarget.
        /// </remarks>
        public static Tween Enqueue(this Tween tween)
        {
            var allTweens = DOTween.TweensByTarget(tween.target);
            if (allTweens == null || allTweens.Count < 2)
            {
                return tween;
            }
            
            tween.Pause();
            var currentTween = DOTween.TweensByTarget(tween.target)[^2];
            currentTween.onComplete += tween.TogglePause;
            
            return tween;
        }
    }
}

Example:

using DG.Tweening;
using UnityEngine;

public class DOTweenQueueExample : MonoBehaviour
{
    System.Collections.IEnumerator Start()
    {
        var t = 1;

        transform.DOMoveX(-0.5f, 0.1f).Enqueue().intId = t++;
        yield return new WaitForSeconds(0.2f);
        transform.DOMoveX(-1f, 0.1f).Enqueue().intId = t++;
        yield return new WaitForSeconds(0.2f);
        transform.DOMoveX(-1.5f, 0.1f).Enqueue().intId = t++;
        
        yield return new WaitForSeconds(3f);
        
        // enqueue on top of long finished tweens:
        transform.DOMove(new Vector3(7.5f, 0f, 0f), 5f).Enqueue().intId = t++;
        yield return new WaitForSeconds(1f);
        
        transform.DOMoveY(5f, 5f).Enqueue().intId = t++;
        yield return new WaitForSeconds(1f);

        transform.DOScale(Vector3.one * 2, 5f).Enqueue().intId = t;
        
        foreach (var tween in DOTween.TweensByTarget(transform))
        {
            Debug.LogError(tween.intId);
        }
    }
}

Is there a better way to do this?

robertocaldas avatar Dec 07 '23 00:12 robertocaldas