OnPlay callback issue
« on: May 29, 2015, 04:39:52 AM »
Hi!,

just to be sure it is not only me, OnPlay callback isn't get called when using <tweener.Restart()> more than once. It will get call the first time only. At the moment I'm doing <tweener.Rewind(); tweener.Play();> to get it call each time. Is it by design?

Thank you.
David

*

Daniele

  • Dr. Admin, I presume
  • *****
  • 378
    • View Profile
    • Demigiant
Re: OnPlay callback issue
« Reply #1 on: May 29, 2015, 10:22:58 AM »
Hi!

OnPlay is fired when a tween changes from a paused state to a playing state. So when calling Restart, OnPlay will fire if the tween was paused, otherwise not. Calling Rewind + Play always fires it instead, because Rewind rewinds+pauses, so when you call Play after that, you're actually changing its playing state.

Cheers,
Daniele

Re: OnPlay callback issue
« Reply #2 on: May 29, 2015, 10:07:13 PM »
Nice thank you! Is there a way to have a OnRestart Callback? Yeah I know that is a lazy request :P because I can Rewind and Play with the OnPlay callback hehe

Re: OnPlay callback issue
« Reply #3 on: May 30, 2015, 01:50:04 AM »
Ok finally, we really need a OnRestart callback. With sequence, doing Rewind and play isn't working. Here's an example:

Code: [Select]
            _sequence = DOTween.Sequence().SetAutoKill(false).SetUpdate(true);
            _sequence.Append(TheGraphic.DOFade(1f, 3f)
                .OnPlay(() =>
                {
                    TheGraphic.gameObject.SetActive(true);
                    Debug.Log("ENABLE GAMEOBJECT");
                })
                .OnComplete(() =>
                {
                    TheGraphic.gameObject.SetActive(false);
                    Debug.Log("DISABLE GAMEOBJECT");
                }));
            _sequence.Append(TheGraphic.DOFade(0f, 3f)
                .OnPlay(() =>
                {
                    TheGraphic.gameObject.SetActive(true);
                    Debug.Log("ENABLE GAMEOBJECT");
                })
                .OnComplete(() =>
                {
                    TheGraphic.gameObject.SetActive(false);
                    Debug.Log("DISABLE GAMEOBJECT");
                }));

Calling
Code: [Select]
_sequence.Restart()or even
Code: [Select]
_sequence.Rewind();
_sequence.Play();

is calling each OnPlay callback of each DoFade to enable de gameobject only the first time and as you said this is by design. But we really need a way to have a callback that will get our gameObject.SetActive(true) each time we restart or rewind-play our sequence. That is just an example code that I could do TheGraphic.gameObject.SetActive(true) in an AppendCallback(), but our code use a manager that return tweener with OnPlay and OnComplete callback on them. So the "TheGraphic" gameObject isn't accessible from our script that is creating the sequence, so it needs to call the OnPlay callback each time we rewind-play it or restart it.

Not sure if I lost you :P
Thank you.
David

*

Daniele

  • Dr. Admin, I presume
  • *****
  • 378
    • View Profile
    • Demigiant
Re: OnPlay callback issue
« Reply #4 on: May 30, 2015, 02:52:14 AM »
OnPlay inside nested elements of a Sequence is indeed a complex beast. But can't you add an OnPlay to the Sequence itself, rather than to the nested tweens, and enable/disable all elements when the Sequence itself restarts (as in rewinds+plays)/completes?

I say this because I really would want to avoid another callback, since even if not used it would still add 4B to every Tweener/Sequence :P

Re: OnPlay callback issue
« Reply #5 on: May 30, 2015, 04:26:37 AM »
We need this, because we are implementing utility function to avoid more coding. Here's an example:

Code: [Select]
        public Tweener Fade(bool fadeIn, float duration)
        {
            return Background.DOFade(fadeIn ? 0f : 1f, duration)
                .OnPlay(() =>
                {
                    if (fadeIn) return;
                    Background.gameObject.SetActive(true);
                    Debug.Log("ENABLING");
                })
                .OnComplete(
                    () =>
                    {
                        if (!fadeIn) return;
                        Background.gameObject.SetActive(false);
                        Debug.Log("DISABLING");
                    })
                .SetEase(FadeEase);
        }

This function will take care to enable the gameObject if it is a fadeOut, fading it, and disabling it if it is a fadeIn. This way we just call from other scripts this line of code:

Code: [Select]
FaderManager.Fade(false, 1f);
and it will take care of enabling the gameObject and disabling it. So no need to take care of that everywhere. Plus, we also want to create some other utility function that will take care of things automatically and we will only call one line of code to achieve it. Of course, at the moment, I already wrote our script without using the OnPlay callback but each time I'm calling FaderManager.Fade() I need to call FaderManager.Background.SetActive(true) before. So I have plenty of FaderManager.Background.SetActive(true) inside of my sequence because this is a kind of cinematic with plenty of fading effect at interval of time.

That is why I thought having a OnPlay callback (or OnRestart) that will be sure to be call each time we play the tween will be useful. The OnComplete is call each time, but there is no callback that is call on each Start (not only the first one as OnStart does).

Maybe changing the OnPlay callback to be sure it will be call each time a tween is starting? I understand that 4B is too much ahah, even me I hate GC! I'm caching a lot of tweens that are used a lot in my game. And on that point, I'll have another question ;) Using more than one time the same cached tween inside of the same sequence is working on the first call, but not on all the other call. (I have try rewinding it and all other thing but without success :().

Code: [Select]
            _cachedTweener = DOTween.To(...); // CACHED TWEEN
            _sequence.Append(_cachedTweener); //THIS ONE WILL WORK
            _sequence.Append(_cachedTweener); //THIS ONE WON'T WORK

Thank you for your time!
David

*

Daniele

  • Dr. Admin, I presume
  • *****
  • 378
    • View Profile
    • Demigiant
Re: OnPlay callback issue
« Reply #6 on: May 31, 2015, 08:32:42 PM »
I still think (because we all hate 4B :D) that it might be done differently. Check the example package I'm attaching (requires but doesn't include DOTween) with a similar approach. That way, you would simply create a reusable tween at startup, and your Fade method should take care directly about activating/deactivating its gameObjects.

About nesting a tween more than once, that is absolutely forbidden! You're not nesting a clone of a tween, but the tween itself, so it can be used only once. You should get a warning when you try to do that, and if you don't I'll check out why you're not getting it.

Re: OnPlay callback issue
« Reply #7 on: June 01, 2015, 10:08:51 PM »
Hi,

your example is almost exactly what I've done and yeah it works in that specific case. But what we want to do was more template tween helper functions. Like:

Code: [Select]
public static Tweener FadeGraphic(Graphic graphic, bool fadeIn, float duration){
return graphic.DoFade(fadeIn ? 0f : 1f, duration)
.OnBegin(() => { if(!fadeIn) graphic.gameObject.SetActive(true); })
.OnComplete(() => { if(fadeIn) graphic.gameObject.SetActive(false); })
.SetUpdate(true)
.SetAutoKill(false);
}

or

Code: [Select]
public static Tweener CrossFade(AudioSource source, AudioClip clip, duration){
return ...;
}

So the programmer will have the possibility to cache the "template" tween in any specific script without having to care about setting the callbacks:

Code: [Select]
Tweener cachedTween = TweenHelper.FadeGraphic(specificGraphic, true, 4f);
...
...
cachedTween.Restart();

Anyway, not sure if I'm explaining well my point :P and why I can't see another way to achieve this without having a OnBegin callback that will be sure to be called on each Start. That was only a suggestion :), and we will live with the way DOTween works without a problem :)

Another suggestion (and do whatever you want with it). The obstacle here is the 4B, and I understand it very well. So I though about something you could implement. I don't know exactly how DOTween works behind the scene so it could be impossible, but maybe implementing a setting to choose which callbacks you need in your project. This way developers could save some memory:

OnPlay -> On/Off
OnStart -> On/Off
OnComplete -> On/Off

and in your DOTween manager having some C# Preprocessor Directives:

Code: [Select]
#if OnPlay
     public TweenCallback OnPlayCallback = null;
#endif

#if OnPlay
     public Tweener OnPlay(this Tweener tweener, TweenCallback callback)
     {
          OnPlayCallback = callback;
          return this;
     }
#endif

#if OnPlay
     if(OnPlayCallback != null)
          OnPlayCallback .Invoke();
#endif

Yeah, that will be a lot of job! That is just some ideas :P

For you warning question. No i don't get any warning while I'm using nested tween more than once inside a sequence unfortunately :(.
Here's a small script to test if it was working ;):

Code: [Select]
    public class TestCachedTween : MonoBehaviour
    {
        private Sequence _sequence;
        private Tweener _cachedTween;
        public float TestedFloat = 10f;


        private void Start()
        {
            _cachedTween = DOTween.To(() => TestedFloat, x => TestedFloat = x, 0f, 5f).SetUpdate(true).SetAutoKill(false).OnComplete(() => {Debug.Log("COMPLETE CACHED TWEEN");});
            _sequence = DOTween.Sequence().SetUpdate(true).SetAutoKill(false);
            _sequence.Append(_cachedTween); //Is called
            _sequence.Append(_cachedTween); //Is not called
        }

        private void Update()
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                _sequence.Restart();
            }
        }
    }

Ok I finish to write by book! Hope you didn't fall asleep while reading it :P

Thanks a lot for your time!
David
« Last Edit: June 01, 2015, 10:10:26 PM by David Racine »

*

Daniele

  • Dr. Admin, I presume
  • *****
  • 378
    • View Profile
    • Demigiant
Re: OnPlay callback issue
« Reply #8 on: June 11, 2015, 01:21:51 AM »
Agh! :O My deepest apologies David! I admit that the wall of text scared me, and I initially postponed it for a few hours while I was taking care of other tween things. But only now I realized I completely forgot about it. Sorry!


The preprocessor directive idea is very nice, and I love preprocessor directives, but that is actually the only con of having DOTween as a DLL: I can't play with preprocessor directives like that.


I'm adding OnPlay to my "maybe" list, and will investigate it more ;)


About the missing warning, my bad. I just realized I take care of that by ignoring new tweens if they're already nested, but I don't dispatch any warning. Added to my "quick todo" list.


Cheers :)