Jump to content
GreenSock

bQvle

Stepping the Ticker manually

Go to solution Solved by GreenSock,

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

Hi Again,

 

I had a thread a couple days ago about using the GSAP Ticker for my game. You actually told me that it wasn't possible to manually step the ticker. but I'll share my concerns, and hear you out.

 

The problem with "RequestAnimationFrame/Your-ticker" is that when you "blur/change browser tab/minimize" it isn't getting called anymore. the result of this is that all animations pauses.

 

This might not be a problem for banners/website animations, or for that sake, singleplayer games.

 

But in my case, it's a problem. I'm creating a browser MMO(serverside) top down wargame, and this is some of the conciquenses i face when the animationloop stops.

 

1. Animations freezes and no longer represents whats actually going on, serverside.

2. 3d sound positions freezes, because they are relative to the gameobjects current position. (gives you the feeling of a game crashing).

3. Ability cooldowns pauses. (getting desynced with the acutual cooldowns running serverside)

4. since theres always thrown new animations at the client, they stack up. (and if you are tabbed for 10 minutes and return, the amount of pending animations will crash the game or atleast make an inferno)

 

 

The solution i had with my own gameloop, was that I timestamped every run, if it got more than 1000 ms old, i manually called my gameloop funtion with a delta of 1 (1000 ms). that made sure everything continued in the background, even while minimzing the browser/changing tab.

 

 

Do you have any idea how I can overcome this? If not, take this as a feature request ;)

 

It would be cool with something like TweenLite.ticker.update(delta) that would manually tick with the supplied delta.

 

og maybe build in an option like "keepAlive" that makes sure the Ticker never stops (even if requestAnimationFrame isn't called).

Link to comment
Share on other sites

Hi bQvle  :)

 

if i understood correctly , you can turning off the requestAnimationFrame ,

 

pls try this :

TweenLite.ticker.useRAF(false);
  • Like 1
Link to comment
Share on other sites

 

Hi bQvle  :)

 

if i understood correctly , you can turning off the requestAnimationFrame ,

 

pls try this :

TweenLite.ticker.useRAF(false);

 

Thanks, but when the windows is active, I want to use RequestAnimationFrame (for smoothness).

 

I could then detect if the loop is running, and toggle useRAF, but that would require me to do the oposite detection when they return to enable "RAF" which might not be as easy.

 

and the biggest "no no" is that I would still lose control over the delta-time. when I detect that the ticker is no longer running, i need to push it forward with the time elapsed since it stopped. 

Link to comment
Share on other sites

To add to Diaco's great advice :)

 

You could detect when the browser tab or browser window gains or loses focus and then pause() and resume() your tweens or timeline.

 

the below example uses the HTML5 Visibility API to detect browser tab / window focus:

 

See the Pen sxgJl by jonathan (@jonathan) on CodePen

 

and then do as Diaco had suggest to toggle useRAF

 

just a suggestion :)

 

GSAP ticker Docs:

http://greensock.com/docs/#/HTML5/GSAP/TweenMax/ticker/

  • Like 2
Link to comment
Share on other sites

To add to Diaco's great advice :)

 

You could detect when the browser tab or browser window gains or loses focus and then pause() and resume() your tweens or timeline.

 

the below example uses the HTML5 Visibility API to detect browser tab / window focus:

 

See the Pen sxgJl by jonathan (@jonathan) on CodePen

 

and then do as Diaco had suggest to toggle useRAF

 

just a suggestion :)

 

I don't want animations to pause, thats what I'm trying to avoid.

The cruscial point for me, is the integrity of time.

 

I could however use your codepen to put together an example.

 

I have stripped window fucus/blur, since that doesn't affect requestAnimationFrame.

And changed it to toggle ticker.useRAF

 

See the Pen PqrjVg by anon (@anon) on CodePen

 (edit: forgot to save, it should be working now)

 

You will see that ActualTime and AnimationTime is instantly desynced when you minimize / change browser tab.

Actually I suspect that it partially works, because you see that it changes back from (not using RAF at 10fps) to using RAF.

Maybe it doesn't call the events(in this case onRepeat) while tabbed. but that would be a problem aswell.

 

Edit2: the white ball doesn't move while tabbed. so maybe its toggling RAF that isn't working, and only the fps that gets toggled.

Link to comment
Share on other sites

Are you seeing different behavior in different Browsers.. like Firefox versus Chrome?

 

Also i believe that different browsers treat RAF different due to it being implemented differently in each browser, since the spec is not standardized yet.

 

Maybe the Honorable Senseis'  Jack or Carl can chime in regarding the GSAP ticker

Link to comment
Share on other sites

It works in Internet Explorer, but i suspect IE is ignoring RAF and forsing 60fps. My game also runs 60fps in IE, even though i have a 120hz monitor and should be running 120fps.

 

Chrome and Firefox is the same result, time stops while tabbed. 

 

Lets try summon a Sensei ;)

Link to comment
Share on other sites

You can use performance.now() to measure time. It's the same high resolution timer used by RAF, and is also a good way to measure how long it takes to execute a callback. Date.now() is not accurate and will shift over time, like every 15 minutes or so.

 

And you're not going to get 120fps since RAF is capped by the browser.

 

You could rework this to be more accurate, but it was just to give you an idea.

 

See the Pen oXroyE?editors=001 by osublake (@osublake) on CodePen

  • Like 3
Link to comment
Share on other sites

Hi blake,

 

Thank you for the info, it was merely for the example, but it's great to know.

 

That's sort of an solution, but my scenario makes it a bit more complex.

The game will be running all sorts of animations, visual effects, missiles, planes, gui animations etc, with various attached functions. only some of them will be timelines.

 

With you method I would have to convert everything into timeLineMax and use setInterval to set totalTime of every timeline (which would proberly ignore some onEvents?) it would have to step my gameloop aswell.

 

It will be alot of work. and I dont feel this is a great solution in my case.

 

but if just "TweenMax.ticker.useRAF(false);" actually worked in this codepen, That would be a great solution.

See the Pen PqrjVg by anon (@anon) on CodePen

 

Edit:

I just tried starting it with TweenMax.ticker.useRAF(false);.

And indeed it is working (animation is very choppy). But it still pauses on "tab blur".

 

this would tell that its actually GSAP thats stopping the ticker when it's not visible?

Link to comment
Share on other sites

That was just a quickie way to show you how it works because that is what the example was using. You can set it up to call your render method and you can use TimelineMax.exportRoot() to do the updates on.

Link to comment
Share on other sites

Then it would have to be something like this?

deferred = setInterval(function() {
  var total = (now() - start) / 1000;
  var tl = TimelineMax.exportRoot();
        
  //move the animations
  tl.totalTime(total);
        
  //do gamelogic and renderer 
  gameloop(1);
}, 1000);

But that still wouldn't quiet work, because the "start" variable you set is for a single timeline, and doesn't really exsist in this snippet. Then you would need to know when every single animation was started and to calculate the totalTime for each of them.

 

Lets see if it's possible to keep the Ticker alive. that would be alot less of a headach :)

Link to comment
Share on other sites

I used start like that because of how you were displaying the total time. But forget that I was even messing with a timeline. You would calculate the actual time elapsed and call setTimeout based on the time difference from the last frame, just like RAF. 

 

I tell you this because it works. I once did something along the lines of...

var delta, time, current;
var last = now();
var fps = 1/60;

function someLoop() {
  
  current = now();    
  time  = tl.totalTime();
  delta = (current - last) / 1000;
  last  = current;
  
  // Update
  while(delta > fps) {    
    delta -= fps;
    time  += fps;
    tl.totalTime(time);
  }  
    
  // Render
}
  • Like 2
Link to comment
Share on other sites

So apparently this is how the fps are calculated in RAF: 1000 / (16+N) = fps, where N is the elapsed time, and fps is clamped at 60. You could use that to figure out when to call your loop and keep everything synced.

  • Like 1
Link to comment
Share on other sites

Ahh okay, sorry about that, I'm not that familiar with GSAP yet, I discovered it just a few days ago. but I'm trying to get up to speed fast. :)

 

This would work as a solution, and I really appreciate all your help and time you've given me!

 

But I'll leave it open a bit for now, I'm pretty "concervative" when it comes to things like this. (I'd rather "fix the core" then taking shortcuts" if you know what i mean).

And in the end, keeping the ticker alive is the best/right solution.

 

So i hope one of the devs will throw a comment on that matter.

Link to comment
Share on other sites

It's cool. But I don't know if this is something that Jack will change.

 

FWIW, I'm kind of messing around with timing issues right now. As a matter of fact, I stumbled upon one of your issues on GitHub for Pixi Particles. I've been having a hard time getting the first couple hundred of ms in sync with GSAP, so I think I'm just going to make my own particle container and use a timeline as the movie.

Link to comment
Share on other sites

  • Solution

Sorry, I haven't had much time to read this post, but from a cursory glance isn't this just a matter of disabling the lagSmoothing feature that's baked into the engine? 

TweenLite.lagSmoothing(0);

?

 

See http://greensock.com/gsap-1-12-0 for more details about the feature.

  • Like 2
Link to comment
Share on other sites

Hi Jack,

 

Brilliant, that did the trick :) I didn't know that exsisted.

 

Heres an updated version that shows the result, you can pop out the Developer tool and watch in console whats happening when minimizing etc. and that it indeed keeps ticking now!

See the Pen PqrjVg by anon (@anon) on CodePen

 

This happends on "Tab Blur"

TweenMax.lagSmoothing(0);
TweenMax.ticker.useRAF(false);

And is reversed on "Tab Focus"

TweenMax.lagSmoothing(500,32);
TweenMax.ticker.useRAF(true);

@blake, thumbs up for effort ;) but I'm relieved that I can keep it uncomplicated now :)

  • Like 1
Link to comment
Share on other sites

Sorry, I haven't had much time to read this post, but from a cursory glance isn't this just a matter of disabling the lagSmoothing feature that's baked into the engine? 

TweenLite.lagSmoothing(0);

?

 

See http://greensock.com/gsap-1-12-0 for more details about the feature.

 

 

Hi again :)

 

I've now switched the game to using TweenMax.ticker, and its still not perfect. (acceptable but not perfect)

when minimized it actually only runs 1fps, I didnt notice that in the codepen, because I only only logged once pr. second :)

 

Is there a way I can make it run more then one fps?

 

Not that I can't live with it, but it still causes the 3d sound to take huge steps, and it throws my client interpolation a bit off for a short time. but atleast the code is getting excuted :)

Link to comment
Share on other sites

The ticker is based on requestAnimationFrame which is COMPLETELY dependent on the browser (as it should be). The browser "powers down" the requestAnimationFrame event dispatching significantly when the tab is inactive in order to reduce CPU load and maximize battery life. So no, we can't tell the browser to dispatch those events more frequently. You're welcome to switch to a setTimeout()-driven ticker by calling TweenLite.ticker.useRAF(false) if you prefer, but as you know there are consequences to that choice as well. I wouldn't really recommend it. 

 

I wish I had a super simple magic bullet for ya :)

Link to comment
Share on other sites

 

This happends on "Tab Blur"

TweenMax.lagSmoothing(0);
TweenMax.ticker.useRAF(false);

And is reversed on "Tab Focus"

TweenMax.lagSmoothing(500,32);
TweenMax.ticker.useRAF(true);

 

But I am actually toggeling useRAF aswell, if i didn't do that time would actually stop (not even run 1 fps)

 

So the 1fps is setTimeout()-driven.

 

 

Edit:

I just did some testing.

 

with 

TweenMax.ticker.useRAF(false);

it runs 1 fps (1000ms)

 

and with

TweenMax.ticker.useRAF(true);

it runs 0.33fps (3000ms)

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.
×