Jump to content
Search Community

Wisdom of using TweenMax as a complete replacement for setTimeout and setInterval?

Halcyon test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

It seems like you could replace all of your setTimeout and setIntervals in your code using something simple like:

var foo=0;
TweenMax.to(foo, 1, {
    onComplete:function(){
        // do something
    }
});

Of course you could use repeat:-1 and onRepeat to make this a setInterval, too. Note that I Tween a generic variable as opposed to a DOM element to avoid the cost of accessing the DOM. Now this comes with several benefits such as the ability to pause, resume, or even killing all timers with a one-line command (which is very useful for me).

 

I made a DOM-based webgame that is entirely timer and event driven, meaning that it was designed without using any game loop at all. Upon discovering the ability to use something like TweenMax.pauseAll(), I realized it would actually be possible to pause all animations, and even timers, if I changed my setTimeouts to TweenMax timers instead. Implementing a pause feature in my game would be a pretty big deal. So is this a good idea?

 

I also noticed that chained setTimeouts tend to lose their timing while TweenMax does not. For example I have button timers that indicate the number of seconds remaining until a skill button is ready to be used, and it updates the seconds remaining every second. In reality the setTimeout is actually running a little bit late depending on how busy the processor has been, but if I use TweenMax timers, it will always be very precise and every second is almost exactly one second of delay (notably, setInterval does not appear to suffer from this timing problem).

 

I particularly noticed this when I developed analog clocks for my website at work and I noticed that all four clocks kept absolute perfect timing no matter how much was going on or how long the webpage was running. Very cool.

 

Any thoughts or feedback on this? I have over 1000+ setTimeouts/setIntervals throughout 70,000+ lines of code so this would be a drastic re-work.

Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

You can definitely use GSAP as a timing mechanism in a few different ways.

 

One option is, as you point in your code, to use callbacks in order to execute different functions. Also keep in mind that the callbacks in the config object also have options to pass parameters to the functions and set the scope in them as well (this is not vastly used, but I've seen some very solid uses, when necessary).

 

A second option is use the delayedCall() method, which acts like a setTimeout.

 

http://api.greensock.com/js/com/greensock/TweenLite.html#delayedCall()

 

The cool thing about delayedCall() is that it has the same options as any callback event, that is you can pass parameters and set a scope to the function. The COOLEST thing about delayedCall() is that it returns a TweenLite instance (when invoked with TweenLite of course), that means you can: play() - pause() - restart() - resume() - timeScale() - seek() - etc. In other words the whole GSAP enchilada right there. Is a very powerful tool for this cases.

 

A third option, when using timelines is the use of add() and call(), on top of the regular timeline callbacks and the nested instances callbacks as well. As you can see, in this scenario the rabbit hole goes as deep as you want. You can define some callbacks to the parent timeline, then you can add callbacks to the instances nested in the timeline, you can also put a call() method in the timelne (which also accepts parameters and scope, and also you can position in the timeline AT ANY TIME YOU WANT!!) and finally you can use the add() method to put a delayedCall() instance that you defined earlier in your code and is stored in a variable.

 

All of this is what makes the engine so powerful in terms of being more than just an animation framework.

 

In terms of your particular scenario is easier to use the delayedCall() method, because is less code than writing a bunch of TweenLite instances, and since version 1.12 there's a lot more control when the hardware is too busy, that's why your sync is much better:

 

http://www.greensock.com/gsap-1-12-0-performance/

 

My guess is that the delayedCall() methods should work under those performance enhancements as well, but It'd be better if Carl or Jack could confirm that.

 

Happy Tweening!!

  • Like 2
Link to comment
Share on other sites

Yup, as Rodrigo said, TweenLite.delayedCall() will essentially create a TweenLite instance with an onComplete callback, which affords many conveniences like play() and pause().

 

To pull some important info from the link Rodrigo shared, if you need absolute precision timing where callbacks fire at the precise time they were scheduled to fire, you should disable lagSmoothing via TweenLite.lagSmoothing(0).

 

When lagSmoothing() is enabled it allows animations to smoothly recover from CPU hiccups by doing some clever time-shifting. 

 

--

 

If you chain delayedCalls() recursively you may lose some time accuracy simply do to the fact that function calls take some time.

//some drifting may be introduced between function calls
function run() {
  console.log("tick");
  delayedCall(1, run)
}

Your idea of using a repeating tween will most likely give you very solid accuracy. 

  • Like 2
Link to comment
Share on other sites

Oh, my goodness! delayedCall is perfect! It's also much less typing than my initial solution, so that's even better! So all I would have to do is replace all of my setTimeouts and setIntervals with delayedCall and then simply execute:

TweenMax.pauseAll();

All without a game loop? This is amazing. I can't believe it's this easy.

 

That third option seems more technical and perhaps not the right choice for my scenario, but I will look into it to learn more. I haven't used add or call much. Though I have used timelines to chain multiple animations together... like 2-4 animations in a row (monster attack animations) because it's much less code than using a ton of onCompletes or even delays. In fact I usually create a function to shorten the code needed:

function TM(){ return new TimelineMax(); }

And then I just do:

var e = monster[3];
var tl = TM();
tl.to(e, .2, {left:'-=10', top:'+=15'})
.to(e, .2, {top:'+=20'});
.to(e, .2, {onStart:function(){ doDamage(); }, top:'-=35', left:'+=10'});

The long timeline stuff is perhaps better suited for long, linear animated sequences like introductions? I'm not sure it's the right choice for game animations unless you're making something like Braid where you can rewind the entire level.

Link to comment
Share on other sites

Follow up question: is there an easier way to kill a delayedCall to an anonymous function? Most of my setTimeouts wrap anonymous functions and it will be a pain to name every block of anonymous code. I was thinking this would work, but it does not:

var time1 = 0;

TweenMax.killDelayedCallsTo(time1);
time1 = TweenMax.delayedCall(1, function(){
    console.log('Job is done.');
});

Instead you have to initialize it as a TweenMax instance which is kind of a pain.

var time1 = new TimelineMax();

time1.kill();
time1 = TweenMax.delayedCall(1, function(){
    console.log('Job is done.');
});

Is there an easier way, or is this pretty much what I would have to do? In any case it works great. I just don't want to do it the hard way if there's an easier way. Thanks again!

Link to comment
Share on other sites

Hello Maelfyn,

 

Have you tried to just kill the delayedCall instance?

// define delayedCall instance with anonymous function
var myDelayedCallback = TweenMax.delayedCall(2, function(){
       // anonymous function code goes here
});

// kill delayedCall() instance var
myDelayedCalback.kill();

See the following forum topic for reference:

 

http://forums.greensock.com/topic/8424-clearinterval-equivalent/

 

Does that help? :)

  • Like 3
Link to comment
Share on other sites

Yes, that does help. I think the best answer for me would simply be to get rid of anonymous functions. Naming every timer would be too onerous for me because I'd have to initialize them all, kill them, etc. If I just give it a function name, TweenMax.pauseAll() will work.

Link to comment
Share on other sites

  • 2 years later...

You can restart a delayedCall, but it will start time drifting as the restart call is not being managed by GSAP, so the other 2 methods would be better.

// restart a delayed call
var interval = TweenLite.delayedCall(0.25, function() {
  interval.restart(true);
  // ...
});

// onRepeat callback in a dummy tween
TweenMax.to({}, 0.25, {
  repeat: -1,
  onRepeat: function() {
    // ...
  }
});

// create a new ticker object
var ticker = new com.greensock.Ticker(4);
ticker.addEventListener("tick", function() {
  // ...
});

See the Pen 10470cf1a6bbfaffa5363f65e6a358d0?editors=0010 by osublake (@osublake) on CodePen

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...