Tasharen Entertainment Forum

Support => NGUI 3 Documentation => Topic started by: ArenMook on November 23, 2013, 05:03:46 AM

Title: Tweens
Post by: ArenMook on November 23, 2013, 05:03:46 AM
Overview

NGUI comes with a small but powerful Tween library.

(http://www.tasharen.com/ngui/tweenwidth.jpg)

To add a tween to a widget, you can right click on it and choose the appropriate selection from the Tween menu. Alternatively, or if you are not selecting a widget, you can go through the NGUI menu (NGUI -> Tween). Last but not least, you can also simply add the appropriate script by name, if you prefer.

Regardless of the route you take, once you add a tween to an object, that tween will be active by default, and as soon as you hit Play you will notice that the tween will be playing. If you don't want it to play right away, simply disable the component by unchecking the checkbox next to the script name.

Although there are a variety of different tweens, they all inherit from the same base class (UITweener (http://tasharen.com/ngui/docs/class_u_i_tweener.html)) and have the same common functionality. They all have a From and a To fields representing the starting and final values. They also all have an Animation Curve that lets you fine-tune how the values will interpolate from one to the other.

The Duration field lets you specify how long it takes for the tween to fully animate, in seconds. You can also add a Start Delay in case you don't want the tween to play right away. This value is also in seconds.

Tween Group lets you have several similar tweens on the same object, and trigger them selectively by matching the group ID.

Now speaking of triggering tweens, you can do so manually by calling their Play() function by specifying the function in the OnClick section on the button, for example.

(http://www.tasharen.com/ngui/onclicktw.jpg)

You can also take a more advanced route by attaching a UIPlayTween script (Attach -> Play Tween Script). It gives a fair bit more options for you to play with.

(http://www.tasharen.com/ngui/uiplaytween.jpg)

First you will want to specify a Tween Target. This will be the game object that will have the tween, or several tweens, that you will want to trigger. You can also optionally make it activate tweens on all child objects by marking the Include Children option.

Like in the actual tween above, the Tween Group field lets you be selective about which tweens you will trigger.

Trigger condition lets you specify what kind of action will trigger the tween to play. Play direction lets you choose which way it will play. If the target is disabled, you can choose to activate it or let it remain disabled (This includes tweens that were marked disabled on purpose so they wouldn't play right away, in case you're wondering!)

If the tween is already playing you can choose to restart it from the beginning, have it continue from where it is, or have it restart only if it already finished playing. You can also have the tween disable the target When finished -- a useful thing to do when you are using tweens to transition from one menu to another.

Finally, if you want to execute some remote function once the tween finishes playing, you can do so by dragging the targeted game object into the Notify field and choosing the appropriate function from the list. Like all NGUI notifications it must be of "public void FuncName (void)" type, like this:
  1. public void MyNotification ()
  2. {
  3.     Debug.Log(UITweener.current.name + " has finished playing!");
  4. }

Pro-Tips
  1. TweenPosition.Begin(tweenGameObject, duration, targetPosition);

Class Documentation

http://tasharen.com/ngui/docs/class_u_i_tweener.html

If you have a question regarding this component or would like me to clarify something, just post a reply here.
Title: Re: Tweens
Post by: OnlineCop on November 26, 2013, 07:28:46 PM
Could you provide an example of chained tweens? Like how to scale up an object, then rotate it once, then scale it back down?
Title: Re: Tweens
Post by: ArenMook on November 26, 2013, 09:27:54 PM
Have you seen this? http://www.youtube.com/watch?v=OT0hTxjjkY4&list=UUQGZdUwzE8gmvgjomZSNFJg#t=881

I create several chained tweens in that video where each tween finishing triggers another.
Title: Re: Tweens
Post by: OnlineCop on November 26, 2013, 11:50:58 PM
I may have missed it, but does this also provide details on how to chain Tweens via code?

http://www.youtube.com/watch?feature=player_detailpage&v=uNSZsMnhS1o#t=73 discusses changes to how tweens work and are called, but it does not go into chaining them.
Title: Re: Tweens
Post by: ArenMook on November 27, 2013, 12:36:51 AM
No that video just talks about how to upgrade.
Title: Re: Tweens
Post by: uberalles on November 27, 2013, 01:17:22 AM
This reply is really meant for Aren, I thought others might be in the same situation though. First off, these documentation posts look great/helpful. My only problem is that most tutorials cover pre-3.x versions of NGUI and I was wondering if you knew of some sort of learning project or tutorial that would be a great starting place for the newer version(s) (just bought NGUI this afternoon so I'm pretty new to the whole thing).

Thanks in advance for any advice you can offer.
Title: Re: Tweens
Post by: ArenMook on November 27, 2013, 01:26:44 AM
The videos I have linked at the top of the Overview (http://www.tasharen.com/forum/index.php?topic=6754.0) post are all for 3.0+. Although with 3.0.6 creating UIs is quite a bit easier now that you can just drag & drop prefab controls directly into your scene to get started, so I'm going to have to redo them (again) soon. I'm thinking with 3.0.7 layout system changes. Anything in particular you want covered more thoroughly?
Title: Re: Tweens
Post by: uberalles on November 27, 2013, 08:25:25 AM
I feel like I'm complaining even though there's quite a lot of info already on this forum. I was just looking for some sort of tutorial project to work on but I think there's enough to go off of from this forum. If you were to make another video I wouldn't mind seeing something about using UIs within 3D space, having a menu pop out of an object for example.
Title: Re: Tweens
Post by: zipper on November 28, 2013, 11:47:39 PM
Many GUIs I create need something to trigger when the tween is finished moving forward, and a different set of things to trigger when the tween is finished in reverse.

Is this something that could be added? Or am I missing something obvious that is already in NGUI?

I was thinking of:
OnFinishedForward
OnFinishedReversed
Title: Re: Tweens
Post by: ArenMook on November 29, 2013, 10:42:29 AM
That's an interesting thought, zipper. I can think of a few use cases for something like that... I'll most likely add that feature, thanks.
Title: Re: Tweens
Post by: Ernest on December 12, 2013, 05:37:04 AM
Can't we have a OnEnable() event on UIPlayTween?
Title: Re: Tweens
Post by: chirhotec on December 12, 2013, 11:57:44 PM
I just downloaded the newest version of NGUI, Playmaker the NGUI-Playmaker bridge (https://hutonggames.fogbugz.com/?W1111). The bridge is only set to support 3.0.5, but I thought I'd give it a try and see if it works.

The only problem that I see so far, is that the UITweener Reset function is set to private (by access modifier omission) in one of the latest versions, and the NGUI-Playmaker bridge makes calls to it externally. According to the UITweener documentation, this function is listed under Public Member Functions (http://tasharen.com/ngui/docs/class_u_i_tweener.html#a79fb68d0ae50721d7fe351d8725bbb01). Any reasons not to make it public?
Title: Re: Tweens
Post by: ArenMook on December 13, 2013, 05:53:35 AM
As it turns out, Reset() is a specific keyword within Unity's Monobehaviours. The Reset() function is called every time you choose the "Reset" option from the right-click menu, and is also called as soon as you add the script to the game object -- which is why tweens were assuming the starting value as soon as you added them (which was annoying).

What UITweener.Reset() used to do is now in UITweener.ResetToBeginning().
Title: Re: Tweens
Post by: rain on January 28, 2014, 12:21:35 PM
What happened to the UITweener's OnEnabled function? Where can I find the replacement for this(if such exists) in the new version?
Title: Re: Tweens
Post by: ArenMook on January 29, 2014, 10:43:52 AM
What was in it that you need?
Title: Re: Tweens
Post by: rain on January 29, 2014, 01:24:40 PM
Only the "event" that the tween has been enabled ( i had a class inheriting from uitweener which relied on this )
Title: Re: Tweens
Post by: ArenMook on January 29, 2014, 11:11:07 PM
OnEnable is a generic Unity notification. Remove the "override" from your class, and you're good to go.
Title: Re: Tweens
Post by: rain on January 30, 2014, 11:39:23 AM
Didn't know that. Thanks!  :D
Title: Re: Tweens
Post by: OnlineCop on January 31, 2014, 01:47:18 AM
(Correct any of this if it's wrong, but this is what I've come to understand...)

In order to make use of a tween's onFinished property, create a callback method and assign it via the EventDelegate.Add() method:

  1. void OnTween1Complete()
  2. {
  3.    // ...do stuff here...
  4. }
  5.  
  6. void MyButtonClicked()
  7. {
  8.    TweenScale tweenScale = TweenScale.Begin(gameObject, scaleAnimationTime, new Vector3(1.5f, 1.5f, 1.5f));
  9.    EventDelegate.Add(tweenScale.onFinished, OnTween1Complete);
  10. }
  11.  

Earlier implementations of UITweener allowed code such as:
  1.    TweenScale.Begin(gameObject, 1f, Vector3.one).onFinished += SomeMethod;
  2.  
but that has been deprecated in favor of the new format above.
Title: Re: Tweens
Post by: ArenMook on January 31, 2014, 12:42:58 PM
Yup that's correct. The EventDelegate approach works properly with inspector. System delegate does not.
Title: Re: Tweens
Post by: zf223669 on March 05, 2014, 08:55:19 PM
Now the tween Component can detect OnFinished state, If it could detect OnStart and OnUpdate state would be more Better!
Title: Re: Tweens
Post by: balzaque on March 19, 2014, 02:04:27 PM
Hi,

I'm trying to tween alpha property of a UISprite on a panel that have normals turned on so light can interact with it. When normals are selected the alpha property only sees to accept full values (0 or 1) but not anything in between (like 0.5f). Is this intended or maybe I'm doing something wrong?

Thanks!
Title: Re: Tweens
Post by: ArenMook on March 20, 2014, 02:28:29 AM
I would say check the shader you're using. Maybe it doesn't use alpha as you'd expect? I see no reason why turning on normals would cause alpha tweens to not behave the same as before.
Title: Re: Tweens
Post by: jlpeebles on November 28, 2014, 07:48:02 PM
Ran into an issue trying to re-play a tween with code, I was trying to replay the tween with...
  1. tween.ResetToBeginning();
  2. tween.PlayForward();
This worked, but only if I set ignoreTimeScale off for some reason. Otherwise the tween would complete instantly.
From looking at UIPlayTween the following is correct. (And indeed works fine)
  1. tween.PlayForward();
  2. tween.ResetToBeginning();
Thought I'd point this out as it didn't seem obvious to me.
Title: Re: Tweens
Post by: amraffay on May 02, 2015, 10:19:49 AM
Hi there,

I'm doing a simple app like interface using anchors, with a back button anchored to top left.
I assigned a position tween to anchored back button but it doesnt seem to work as expected.
What i want is that back button sticks to anchors, but when scene is loaded it comes from the left side (hidden area)

How can i achieve that?


Secondly can you please provide something like this officially?
https://unionassets.com/blog/empowerment-tween-animations-in-ngui-278

Thanks
Title: Re: Tweens
Post by: ArenMook on May 02, 2015, 10:13:51 PM
Don't anchor the button. Anchor its parent. Since the button would be a child of an anchored object, you can animate it as you see fit.
Title: Re: Tweens
Post by: amraffay on May 03, 2015, 02:53:17 AM
Got it Thanks
Title: Re: Tweens
Post by: dehinrsu on October 03, 2015, 12:01:11 AM
Hello,

At times the current state of the GameObject may not be the required initial state. Is it possible for you to add an overload Tween.Begin(GameObject, duration, From, To)?

As of now I am using Begin twice to keep the code clean and simple.

TweenAlpha.Begin(gameObject, 0, 0.25f);
TweenAlpha.Begin(gameObject, 0, 1);

Instead of the above, would like to have something like this.
TweenAlpha.Begin(gameObject, 0, 0.25f, 1);


Thanks
Vijay
Title: Re: Tweens
Post by: ArenMook on October 03, 2015, 06:49:37 PM
Tween.Begin returns you an instance to the tween, so just change its from value.
  1. TweenAlpha tw = TweenAlpha.Begin(gameObject, 0f, 1f);
  2. tw.from = 0.25f;
Title: Re: Tweens
Post by: Dune on October 23, 2016, 07:18:54 PM
I noticed this code in TweenWidth. Did you know about the ?? operator? The ?? operator says, "if the value on the left is null, use the value on the right."

  1. public UIWidget cachedWidget { get { if (mWidget == null) mWidget = GetComponent<UIWidget>(); return mWidget; } }
  2. // replace with ...
  3. public UIWidget cachedWidget { get { return mWidget ?? (mWidget = GetComponent<UIWidget>()); } }
  4.  
Title: Re: Tweens
Post by: ArenMook on October 24, 2016, 07:13:50 AM
Yeah I tend to use ?? quite a bit, NGUI is older code though. Thanks, I like that approach.

Edit: After further testing I realized that the ?? operator won't work in the editor properly after a widget has been destroyed. Unity uses a dummy object to facilitate the "trying to use XYZ but it has been destroyed" exceptions, so ?? returns 'true' on the left side, never reaching the right since ?? checks references not being null, rather than running a (bool) conversion or != check on the object. The bool conversion and "!= null" comparison would evaluate as 'false'.
Title: Re: Tweens
Post by: The-Arrival on November 05, 2016, 08:08:54 AM
Ran into an issue trying to re-play a tween with code, I was trying to replay the tween with...
  1. tween.ResetToBeginning();
  2. tween.PlayForward();
This worked, but only if I set ignoreTimeScale off for some reason. Otherwise the tween would complete instantly.
From looking at UIPlayTween the following is correct. (And indeed works fine)
  1. tween.PlayForward();
  2. tween.ResetToBeginning();
Thought I'd point this out as it didn't seem obvious to me.

Thanks... this info was very helpful!

Also if you want to manually (re)set a tween to it´s from state, use: tween.Sample(0, true);
Title: Re: Tweens
Post by: The-Arrival on April 16, 2017, 06:09:07 PM
Hey Aren,

i have the following situation:
Unity 5.5.1f3
NGUI 3.11.2

I´m making a TowerDefense Game

i have a pool of sprites in my UI, all of them carry a tweenposition (disabled by default, so they not play instantly). When a sprite is requested, it gets setup (which sprite to show), the tween gets configured (start/end pos and duration) and the tween is Played forward.
OnTweenFinish the tween gets back into the bool (which means mainly it gets flagged as pooled and the sprite gets disabled.
The tween is set to NOT ignore timeScale (since we have time warp effects and the UI also should animate faster for this very panel)

Most of the time that works fine, but at some point the tweens start to play instantatiously, even the setup is correct (start != end, duration != 0)

As stated in my last post/quote i also tried differen versions of the play/rest combinations.

i used tween.PlayForward() as well as tween.Play(true)
i tried different versions of resetting the tween, like right before or after the play call as well as in the onTweenFinished Callback.

The bug allways happens at the same time, right after the first Wave is finished... in the second Wave the Bug allready is there. So it might be that it´s my fault, but i´m checking my code since hours and i can´t find the difference between wave1 and wave2 and my usage of the tweens.

Any idea what i might do wrong or could that actually be a NGUI bug?

Thanks in advance!

EDIT:

after some additional tests it became more likely that it´s an issue with NGUI.

In my usecase the poolsize was 10 and i reused more or less the same 3 items. at the time the bug occured i was reusing an item whos tween got finished right before it got claimed and used again. So what i did is to make sure that the whole pool got used, before reusing the same item again.
That time the tweens work for much longer (more waves, so it was nothing which happened between wave 1 and 2).
But it got locked again after the first item got reused about 7-8 times... maybe some racing conditions which only sometimes occure?
Title: Re: Tweens
Post by: ArenMook on April 22, 2017, 12:41:46 PM
Did you try calling ResetToBeginning()? If it's already in progress, then it will continue to play from where it was when you play it forward again.

Edit: Noticed this is a continuation of our previous conversation from a few months back and you did use ResetToBeginning there. I assume you still do? Which order are you calling them in this time? Re-reading the post I assume "rest" actually meant "reset", which would imply that the answer is 'yes'. Post some code, that might help also.

P.S. Did you try printing the time and deltaTime that's retrieved at the top of DoUpdate() function? The only difference between ignoring timescale and not ignoring it are the values retrieved there.
Title: Re: Tweens
Post by: The-Arrival on April 26, 2017, 01:28:51 AM
Hi,

yes i did call ResetToBeginning() and tried it on different positions. Right before PlayForward(), right after PlayForward() and in a callback method triggered by the OnFinished Event from your tweener.
I also tried myTransform.localPosition = startPosition in combination with myTweener.SetStartToCurrentValue();

Here are the three main methods currently used. i left the commented calls in, so you get an idea at which positions i tried resets:

  1. public void Setup(PublicEnums.Enemys enemy, bool shield, bool armor, Vector3 startPos, float duration) {
  2.         useCounter++;
  3.  
  4.         //Debug.Log("Setup Sprite: " + myID);
  5.         myRoot.localPosition = startPos;
  6.         mySprite.spriteName = SpriteUtils.getEnemyIconName(enemy);
  7.        
  8.         //Shield and Armor
  9.         if (armor) {
  10.             mySprite.color = Managers.PrefabManager.ui_armorColor;
  11.         }
  12.         if (shield) {
  13.             myShield.SetActive(true);
  14.         }
  15.  
  16.         isUsed = true;
  17.         mySprite.enabled = true;
  18.         myTweener.SetStartToCurrentValue();
  19.         myTweener.duration = duration;
  20.         myTweener.from = startPos;
  21.         myTweener.to = myEndPos;
  22.         //myTweener.ResetToBeginning();
  23.         //Debug.Log("Setup " + myID + ": start: " + startPos + ", duration: " + duration);
  24.     }
  25.     public void StartTween() {
  26.        
  27.         Debug.Log("Setup " + myID + ", pos: " + myRoot.localPosition + ": start: " + myTweener.from + ", end : " + myTweener.to + ", duration: " + myTweener.duration);
  28.         //myTweener.ResetToBeginning();
  29.         myTweener.PlayForward();
  30.         //myTweener.ResetToBeginning();
  31.     }
  32.  
  33.     public void onTweenFinished() {
  34.         myTweener.ResetToBeginning();
  35.         Debug.Log("OnTweenFinished: " + myID);
  36.         isUsed = false;
  37.         mySprite.enabled = false;
  38.         myRoot.localPosition = Vector3.zero;
  39.         myShield.SetActive(false);
  40.         mySprite.color = Color.white;
  41.     }
  42.  

Besides the Debuglogs you can see in the code samples i also added the ones you requested and another one when a tween gets reused from the pool (which is basically invisible and flagged tweens). In the attached screenshot you can see a debuglog output at the time the bug occures.

we use and setup a tween with the ID -47456. It has the right pos, start, end and duration values. three DoUpdates() later the OnFinished Events happen and my OnTweenFinished event is called
Title: Re: Tweens
Post by: ArenMook on April 26, 2017, 07:09:01 AM
In the log I see 2 log entries have the same time, yet different delta... why is that? I also don't see where that debug line is called. You should also keep the tween disabled. Calling PlayForward will already enable it, and that's something that should be done at the end after setting everything up. When you call Play/PlayForward/PlayReverse, it sets the "mStarted" flag -- but only if the tween is disabled. That's important.
Title: Re: Tweens
Post by: The-Arrival on May 02, 2017, 02:20:44 PM
Log Entrys and Debug.Log calls:
I was adding the debug.log call directly in to the DoUpdate funktion in the UItweener... right after delat and time get set

  1. protected void DoUpdate ()
  2.         {
  3.                 float delta = ignoreTimeScale && !useFixedUpdate ? Time.unscaledDeltaTime : Time.deltaTime;
  4.                 float time = ignoreTimeScale && !useFixedUpdate ? Time.unscaledTime : Time.time;
  5.  
  6.         Debug.Log("delta: " + delta + ", time: " + time);
  7.  
  8.  

There are two identical entrys due to the fact that there is more then one tween active and posting their logs.

Enable/Disable:

As you can see in the code i don´t enable/disable the tween component, i only enable/disable a sprite-component and a child gameobject.

Sorry for the little delay in my answers but i´m currently jumping between projects. I´ll answer more frequently from now on.

One strange behaviour i found is, that i get a few of those Debug.Log calls with time and delta, whenever i hover over an UI Element. That might be due to the fact that you use the UITweener class also for button animations? In any case that facts makes it hard for me to use the IDE-Debugger to step through the code

Did you run some tests on your own with reusing/pooling the same tween?
Title: Re: Tweens
Post by: The-Arrival on May 03, 2017, 03:34:58 PM
I´m one step closer i guess and i exactly witnessed the situation in were it happens:

The last time that bugging tween worked was in a special situation. it was set to start roughly equals and and duration 0. As soon as the tween gets started it pretty much immediatly ends. That is on purpose and fine so far!
The next time that tween gets used though i starts to bu and instantly ends it´s animation, even it gets setup with start NOT equals end and duration = 5f;
It seems we have some weired racing condition going on here. My Debug.Log states the correct setup. I was even able to move to the exact frame that tween gets setup and started using the frame-by-frame debugging. In the frame it gets started, the inspector shows the duration of 5f, but my guess is, that it´s still starting with 0f from the last time. If i go one frame further it immediatly ends, calling the OnFinish callback.

I added a little offset to my durations of 0.1f to avoid the 0f duration and voilá, the bug is gone and the tween is behaving correctly.

I hope that helps you tracking down whats going wrong here