Author Topic: UITweener.onFinish not calling  (Read 8481 times)

Ging

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
UITweener.onFinish not calling
« on: July 27, 2014, 07:17:04 PM »
In some cases, when we are have many UITweens in scene, onFinish callbacks not firing.
Problem: UITweener.cs, line 214
  1. if (current == null)
- ignore the callback's code part from "new", when another ("current") tween is finished. And no matter - has "current" onFinished callbacks or not. When I remove this check (and then fully remove it, just save "current" to "temp", set "current"="new" call onFinished, and then restore "current"="temp") issue has fixed.. but.. I did't like this fix, because "current"  maybe used in onFinished and will crash code loginc in same case.

This only one way to fix this issue normally, in my opinion: delete static field UITweener.current and send onFinished events with sender's "this" parameter, like
  1. onFinished.call(this)

Sorry, if my English is not well.

P.S. NGUI 3.6.8

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UITweener.onFinish not calling
« Reply #1 on: July 27, 2014, 11:17:47 PM »
My question is, why do you have one OnFinished being called from inside of another? That just seems wrong to me. The way it is now is to prevent a case when you'd mistakenly call the same tween's OnFinished from inside itself, causing a stack overflow / endless loop.

Ging

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: UITweener.onFinish not calling
« Reply #2 on: July 28, 2014, 03:52:25 AM »
For example.. http://gyazo.com/ecc84ea729dfda30843d122fe207b19e
"Me" - Tween was firing onFinish.. "Current" - UITweener.current;

CallStack:

Me: UI Root (2D).GameUIGroup.GUIPanel.GameField.PlayerField8.Face.AvatarClipPanel.AnimGroup.AnimRoot.AnimTake.AnimTable.CardSprite.ShadowSprite.ShadowSprite (TweenAlpha)
Current: UI Root (2D).GameUIGroup.GUIPanel.GameField.PlayerField8.Face.AvatarClipPanel.AnimGroup.AnimGroup (TweenPosition)

UnityEngine.Debug:LogWarning(Object)
UITweener:Update() (at Assets/Plugins/Library/NGUI/Tweening/UITweener.cs:310)
UITweener:Play(Boolean) (at Assets/Plugins/Library/NGUI/Tweening/UITweener.cs:491)
UITweener:PlayForward() (at Assets/Plugins/Library/NGUI/Tweening/UITweener.cs:469)
AnimTakeController:OnTransitionFinished() (at Assets/Plugins/Controllers/AnimTakeController.cs:47)
EventDelegate:Execute() (at Assets/Plugins/Library/NGUI/Internal/EventDelegate.cs:235)
EventDelegate:Execute(List`1) (at Assets/Plugins/Library/NGUI/Internal/EventDelegate.cs:302)
UITweener:Update() (at Assets/Plugins/Library/NGUI/Tweening/UITweener.cs:274)

AnimTakeController:OnTransitionFinished() code
  1. public void OnTransitionFinished()
  2.     {
  3.         if (!CanNextAnimationPlay)
  4.             return;
  5.         _cardCount = 0;
  6.         _isMePlayNow = true;
  7.         var tweens = GetComponentsInChildren<UITweener>(true);
  8.         foreach (var tween in tweens.Where(tween => !(tween is TweenTimeAction)))
  9.         {
  10.             tween.PlayForward();
  11.         }
  12.         GetComponent<AnimDeckTopController>().StartDeckTopAnim();
  13.     }

Ging

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: UITweener.onFinish not calling
« Reply #3 on: July 28, 2014, 03:54:44 AM »
My question is, why do you have one OnFinished being called from inside of another?
I think it is multi-thread rendernig, but... it's happened and when MTR off.. or "new" tween already has finihed...
« Last Edit: July 28, 2014, 12:50:34 PM by Ging »

Ging

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 6
    • View Profile
Re: UITweener.onFinish not calling
« Reply #4 on: July 30, 2014, 03:27:54 AM »
Got any ideas?

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UITweener.onFinish not calling
« Reply #5 on: July 30, 2014, 10:26:42 AM »
I don't know, it's your project, you tell me: why do you have one OnFinished calling another? Add some Debug.Logs in there to figure out which tween is calling which, and you will find out what's happening.

The only relevant change in the current Pro version in NGUI is line 230 of UITweener.cs adding a "!ed.oneShot" check:
  1. if (ed != null && !ed.oneShot) EventDelegate.Add(onFinished, ed, ed.oneShot);

imperso

  • Newbie
  • *
  • Thank You
  • -Given: 1
  • -Receive: 0
  • Posts: 16
    • View Profile
Re: UITweener.onFinish not calling
« Reply #6 on: April 13, 2015, 03:26:40 PM »
Aren, after updating NGUI I see in UITweener the fix proposed here (when you use "current" variable) ;)

But then we have these two lines
  1.   if (duration == 0f || (mFactor == 1f && mAmountPerDelta > 0f || mFactor == 0f && mAmountPerDelta < 0f))
  2.                 enabled = false;

Previously you placed them before "if (current == null)" check. Now they follow the check. And this change ruins my setup. Could you clarify why did you moved them forward?
« Last Edit: April 14, 2015, 01:01:30 AM by imperso »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UITweener.onFinish not calling
« Reply #7 on: April 16, 2015, 05:19:09 AM »
I am not sure what it was like before as it was a while ago, but you can probably just get rid of that part altogether and move enabled = false; much higher up:
  1.                 if ((style == Style.Once) && (duration == 0f || mFactor > 1f || mFactor < 0f))
  2.                 {
  3.                         mFactor = Mathf.Clamp01(mFactor);
  4.                         Sample(mFactor, true);
  5.                         enabled = false; // <-- right here, no 'if' checks needed
  6.  
  7.                         if (current == null)
  8.                         {
  9.                                 UITweener before = current;
  10.                                 current = this;
  11.  
  12.                                 if (onFinished != null)
  13.                                 {
  14.                                         mTemp = onFinished;
  15.                                         onFinished = new List<EventDelegate>();
  16.  
  17.                                         // Notify the listener delegates
  18.                                         EventDelegate.Execute(mTemp);
  19.  
  20.                                         // Re-add the previous persistent delegates
  21.                                         for (int i = 0; i < mTemp.Count; ++i)
  22.                                         {
  23.                                                 EventDelegate ed = mTemp[i];
  24.                                                 if (ed != null && !ed.oneShot) EventDelegate.Add(onFinished, ed, ed.oneShot);
  25.                                         }
  26.                                         mTemp = null;
  27.                                 }
  28.  
  29.                                 // Deprecated legacy functionality support
  30.                                 if (eventReceiver != null && !string.IsNullOrEmpty(callWhenFinished))
  31.                                         eventReceiver.SendMessage(callWhenFinished, this, SendMessageOptions.DontRequireReceiver);
  32.  
  33.                                 current = before;
  34.                         }
  35.                 }
  36.                 else Sample(mFactor, false);