Author Topic: 3.4.9 Can't reset tween after playing backwards (also exception)  (Read 5661 times)

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
3.4.9 Can't reset tween after playing backwards (also exception)
« on: February 19, 2014, 05:45:46 PM »
As far as I can tell, it's impossible to reset a tween after it has been played in reverse. The easiest way to explain is probably just a code example. I have a popup window that tweens in, waits for a couple seconds, and tweens back out (in reverse). If it's called while already active, it queues the new message and shows it after the current one finishes. If the user leaves the screen it's on, the queue is simply emptied. This means it's possible for the tween to have been disabled in some random state and needs to be reset to it's initial state before being shown.

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3.  
  4. public class PopupTest : MonoBehaviour
  5. {
  6.         #region Editor Interface
  7.  
  8.         [SerializeField] private TweenScale tweener;
  9.         [SerializeField] private int secondsToDisplay;
  10.  
  11.         #endregion
  12.  
  13.         #region Private Fields
  14.  
  15.         private static PopupTest instance;
  16.         private static Queue<string> queue = new Queue<string>();
  17.         private static bool isActive = false;
  18.  
  19.         #endregion
  20.  
  21.         #region MonoBehaviour Methods
  22.  
  23.         private void Awake ()
  24.         {
  25.                 //Enforce the singleton pattern
  26.                 if ( instance != null )
  27.                 {
  28.                         Debug.LogError("Multiple instances of the " + GetType() + " created. There can be only one.");
  29.                 }
  30.                 instance = this;
  31.         }
  32.  
  33.         private void OnDisable ()
  34.         {
  35.                 isActive = false;
  36.                 NGUITools.SetActiveChildren(gameObject, false);
  37.  
  38.                 tweener.onFinished.Clear();
  39.                 tweener.enabled = false;
  40.                 queue.Clear();
  41.         }
  42.  
  43.         private void OnDestroy ()
  44.         {
  45.                 instance = null;
  46.         }
  47.  
  48.         #endregion
  49.  
  50.         #region Public Interface
  51.  
  52.         public static void Display ()
  53.         {
  54.                 if ( !instance.gameObject.activeInHierarchy ) return;
  55.  
  56.                 queue.Enqueue("Test");
  57.  
  58.                 if ( !isActive )
  59.                 {
  60.                         instance.Show();
  61.                 }
  62.         }
  63.  
  64.         #endregion
  65.  
  66.         #region Private Methods
  67.  
  68.         private void Show ()
  69.         {
  70.                 queue.Dequeue();
  71.  
  72.                 EventDelegate.Add(tweener.onFinished, Hide, true);
  73.                 tweener.delay = 0;
  74.  
  75.                 tweener.Play(true);
  76.                 Debug.Log("Scale (play1):" + transform.localScale);
  77.                 tweener.ResetToBeginning();
  78.                 Debug.Log("Scale (reset):" + transform.localScale);
  79.                 tweener.Play(true);
  80.                 Debug.Log("Scale (play2):" + transform.localScale);
  81.  
  82.                 isActive = true;
  83.                 NGUITools.SetActiveChildren(gameObject, true);
  84.         }
  85.  
  86.         private void Hide ()
  87.         {
  88.                 EventDelegate.Add(tweener.onFinished, HideComplete, true);
  89.                 tweener.delay = secondsToDisplay;
  90.                 tweener.Play(false);
  91.         }
  92.  
  93.         private void HideComplete ()
  94.         {
  95.                 isActive = false;
  96.                 NGUITools.SetActiveChildren(gameObject, false);
  97.  
  98.                 if ( queue.Count > 0 )
  99.                 {
  100.                         Show();
  101.                 }
  102.         }
  103.  
  104.         #endregion
  105. }
  106.  

The issues are with Show(). Since the tween could have been disabled while tweening in reverse, I have to play it forward once otherwise ResetToBeginning actually resets it to the end. However, it still doesn't work. If the tween is disabled in the middle of the tween playing in reverse, I can't get it to reset back to the beginning and it will just appear instantly instead of tweening.

Incidentally, if you remove the first Play(true) from Show() the tween will throw an exception when a message is queued.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #1 on: February 20, 2014, 09:11:35 AM »
Why are you calling Play so many times, and why do you register a delegate before calling Play?

First call Play, then register your delegate, and do it only once.

Also, there is a Toggle() function if you are trying to make it go in reverse.

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #2 on: February 20, 2014, 09:20:03 AM »
Why are you calling Play so many times
The tween may have been playing backwards last, so I have to call Play(true) or ResetToBeginning() may actually reset it to the end. ResetToBeginning() sets mStarted to false, so presumably that stops the tweening (I haven't confirmed that), so I have to call Play(true) again afterward.

why do you register a delegate before calling Play?
Instinct? Usually you register for events before you start the thing that could trigger the event. Presumably, there's some non-zero chance the event could be fired immediately. What happens if you start a tween and it's already in the final state? Again, I haven't explicitly tested this, I just would never have expected it to be an issue.

First call Play, then register your delegate, and do it only once.
I'll give this a shot.

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #3 on: February 20, 2014, 10:55:09 AM »
No dice. The popup will appear and just freeze at the final state.

If the popup was disabled while visible, it's already at the final state. Playing forward, the tween will then think it's already completed and stop. ResetToBeginning then sets it to the initial state, but it doesn't know to start playing. Hence my reasoning for having Play, ResetToBegining, Play in the original post.

  1. private void Show ()
  2. {
  3.         queue.Dequeue();
  4.  
  5.         tweener.delay = 0;
  6.  
  7.         //Will freeze if the popup was disabled while in the final state
  8.         tweener.Play(true);
  9.         tweener.ResetToBeginning();
  10.         EventDelegate.Add(tweener.onFinished, Hide, true);
  11.  
  12.         isActive = true;
  13.         NGUITools.SetActiveChildren(gameObject, true);
  14. }
  15.  
  16. private void Hide ()
  17. {
  18.         tweener.delay = secondsToDisplay;
  19.         tweener.Play(false);
  20.         EventDelegate.Add(tweener.onFinished, Done, true);
  21. }
  22.  

Further, it's looks like I was right about the events. If I play the tween forward while it's already in the final state, it will instantly finish (which makes sense). If I haven't registered the handler for onFinished, it will obviously not get called. Thus, if it's possible for the tween to already be finished it's important register before playing.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #4 on: February 21, 2014, 03:28:59 PM »
Alright... enable the object first, then do the tween playing logic.

You might also find it useful to examine the UIPlayTween script. It has all the logic for how to activate and play a tween properly (UIPlayTween.Play function in particular).

AtomicBob

  • Jr. Member
  • **
  • Thank You
  • -Given: 3
  • -Receive: 0
  • Posts: 69
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #5 on: February 21, 2014, 03:31:37 PM »
I'm not sure what you mean. The object is enabled when all of this happens.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: 3.4.9 Can't reset tween after playing backwards (also exception)
« Reply #6 on: February 21, 2014, 03:35:10 PM »
Quote
If the popup was disabled while visible
That suggests to me that it's disabled. When you do all the play logic it's already enabled? In any case, check out UIPlayTween.