Jump to content

Delta time is ruining my animations


forleafe
 Share

Recommended Posts

I'm making a game where the game loop's frame rate is controlled and kept consistent with:

renderer.ticker.add(function(delta){
deltaGlobal = delta;
state();
});

However because of this, it causes my sprite animations to skip frames and look extremely choppy and ugly. Does pixi have a built in way to handle this that I'm just not seeing? Or are we still forced to use external scripts like this:

https://github.com/kittykatattack/smoothie

Obviously if there isn't a built in feature for animations to run smoothly while the framerate is being controlled with a delta, then that might be a pretty essential feature that should get added soon.
 

Link to comment
Share on other sites

57 minutes ago, botmaster said:

There's not really anything special going on here, the delta value you get is about the same you'll get with the smoothie library. You don't have to use the ticker anyway and you can just stop it and provide your own routine. 

I'm not really sure that my issue is being understood, let me try explaining better.

If I don't control the framerate with a delta, then higher end machines will run the game way too fast, in the blink of an eye, while slightly slower machines the game will literally run at a different framerate and possibly lag. I don't think I have any other choice to control this except with a delta, right? That way everything is a constant framerate.

Okay, the issue is that because my framerate is being controlled, for whatever reason, PIXI.extras.animation doesn't at all take whether or not you're using the ticker into account(or does it?). So because of this it's literally dropping animation frames and running like crap. Not being able to control my frame rate and animate sprites smoothly is... sort of a big deal. 

What my mind is sort of blown on is why this isn't already taken into account with pixi's framework. I mean, I think the real question here is, how am I supposed to build an app *without* using a delta and any animations? Without a delta your user's framerate is completely at the whim of whatever the device is. So if I'm using newer hardware, it'll be like playing super mario on 5x speed.

Sorry for the wall, but I'm trying to be thorough to make sure I'm not misunderstanding or missing something. Having to code a way for animations to work with a delta feels like me doing something that is so basic and ubiquitously needed, that I'd be reinventing something that someone already did.

Edit: I feel like I'm struggling to express myself properly. Here's a blurb from Smoothie.js 's page that is pretty much exactly what I want. To keep my frame rates smooth and not gittery.

"You can also add a Boolean interpolate property that defines whether Smoothie should use interpolation (true) or not (false).

interpolate: true

If you set it to false, Smoothie will render the sprites and the update function logic at the same frame rate. That means jittery animation at low frame rates - if that's what you want, you've got it!"

 

Link to comment
Share on other sites

4 hours ago, Exca said:

I use pixis own ticker and so far animatedsprites have worked without any issues. How are you using the animatedsprite?

My sprites are animated with a spritesheet loaded through the pixi loader, the frames are then added to Pixi.extras.AnimatedSprite, and then that animated sprite is added to the container, and then played using (play). It'll play but run choppily.

Just to test out my animation to see if it was the issue, on a separate file that didn't use a ticker, the animation ran smoothly.

Link to comment
Share on other sites

19 hours ago, forleafe said:

I'm not really sure that my issue is being understood, let me try explaining better.

If I don't control the framerate with a delta, then higher end machines will run the game way too fast, in the blink of an eye, while slightly slower machines the game will literally run at a different framerate and possibly lag. I don't think I have any other choice to control this except with a delta, right? That way everything is a constant framerate.

Okay, the issue is that because my framerate is being controlled, for whatever reason, PIXI.extras.animation doesn't at all take whether or not you're using the ticker into account(or does it?). So because of this it's literally dropping animation frames and running like crap. Not being able to control my frame rate and animate sprites smoothly is... sort of a big deal. 

What my mind is sort of blown on is why this isn't already taken into account with pixi's framework. I mean, I think the real question here is, how am I supposed to build an app *without* using a delta and any animations? Without a delta your user's framerate is completely at the whim of whatever the device is. So if I'm using newer hardware, it'll be like playing super mario on 5x speed.

Sorry for the wall, but I'm trying to be thorough to make sure I'm not misunderstanding or missing something. Having to code a way for animations to work with a delta feels like me doing something that is so basic and ubiquitously needed, that I'd be reinventing something that someone already did.

Edit: I feel like I'm struggling to express myself properly. Here's a blurb from Smoothie.js 's page that is pretty much exactly what I want. To keep my frame rates smooth and not gittery.

"You can also add a Boolean interpolate property that defines whether Smoothie should use interpolation (true) or not (false).


interpolate: true

If you set it to false, Smoothie will render the sprites and the update function logic at the same frame rate. That means jittery animation at low frame rates - if that's what you want, you've got it!"

 

I totally understand, what you want is what's called "time based" animation and PIXI doesn't provide that but in fairness most low level frameworks/technologies don't, they provide you with a tick and let you handle the rest. Flash or SriteKit work the same way for example. The smoothy.js I guess is meant to provide that time based feature so go with it.

To further answer your question:

- PIXI correctly doesn't provide any time based feature with its tick system

- that tick system/delta doesn't control the framerate as you said since framerate cannot really be controlled

- the delta value tells you how much time has passed since the last tick, this is what can be used to run a time based system (and this is what smoothie.js uses)

- the real framerate is really how many requestanimationframe can be called per second, while you can lower the number of call by code you certainly cannot increase it so that's really the framerate basis, time based animation doesn't alter the framerate, it calculates what frame an animation should display based on how much time has passed, how many pixels an object should move based on how much time has passed, etc ... 

Link to comment
Share on other sites

12 minutes ago, botmaster said:

- PIXI correctly doesn't provide any time based feature with its tick system

- that tick system/delta doesn't control the framerate as you said since framerate cannot really be controlled

- the delta value tells you how much time has passed since the last tick, this is what can be used to run a time based system (and this is what smoothie.js uses)

 

Pixi ticker deltaTime is not how much time has passed since the last tick, but rather a value telling how much faster/slower game is running than what is intended. You can control the value by setting minFPS and speed on ticker.

Tickers elapsedMS is the absolute value of milliseconds since last frame.

If you are using shared ticker for your app and not your own, then animationsprite should work properly with autoupdate. If on the other hand you have your own update/timer that is not working in same timeline as pixis ticker, then you should manually call update and set autoplay to false on animatedSprites.

Link to comment
Share on other sites

1 hour ago, Exca said:

https://pixijs.io/examples/#/basics/spritesheet.js

Does this run smoothly for you?

Yes, of course it does. ? It's not my machine. Like I just said, I tested my frame animation without the ticker and it immediately ran smoothly like it should. Are you positive the ticker is built to work properly with animationsprites? Because botmaster literally just said the opposite, and I can't see why smoothie.js would even exist if the ticker already had this functionality built in. I can provide some code of mine if needed so maybe we can see more easily what's going on?

 

 

1 hour ago, botmaster said:

I totally understand, what you want is what's called "time based" animation and PIXI doesn't provide that but in fairness most low level frameworks/technologies don't, they provide you with a tick and let you handle the rest. Flash or SriteKit work the same way for example. The smoothy.js I guess is meant to provide that time based feature so go with it.

To further answer your question:

- PIXI correctly doesn't provide any time based feature with its tick system

- that tick system/delta doesn't control the framerate as you said since framerate cannot really be controlled

- the delta value tells you how much time has passed since the last tick, this is what can be used to run a time based system (and this is what smoothie.js uses)

- the real framerate is really how many requestanimationframe can be called per second, while you can lower the number of call by code you certainly cannot increase it so that's really the framerate basis, time based animation doesn't alter the framerate, it calculates what frame an animation should display based on how much time has passed, how many pixels an object should move based on how much time has passed, etc ... 


What would you suggest is the solution to this then? Smoothie.js As I've looked up actually isn't in a working state for pixi v4, and was written for v3. I've asked the developer if he can update his code, but they've been a bit unresponsive lately. Are there any other popular alternatives that people use for timebased animation? I mean, this has to be a pretty common problem for sure.

Link to comment
Share on other sites

12 minutes ago, forleafe said:

I tested my frame animation without the ticker and it immediately ran smoothly like it should. Are you positive the ticker is built to work properly with animationsprites? Because botmaster literally just said the opposite, and I can't see why smoothie.js would even exist if the ticker already had this functionality built in. I can provide some code of mine if needed so maybe we can see more easily what's going on?

At least on my projects I have no problems. Though I don't use the shared ticker. I create a new one and run everything based on that. But I don't see how running with shared vs. running with own could break animatedSprite.

No matter the fps the animated sprites are running at the speed I order them to run. I keep tickers target fps at 60 so deltatimes are around 1 when game is running 60fps, 0.5 when running 120fps and so on. Then in the updateloop I give the delta to update loop and if it has 1 as it's speed then animations run 60fps, if it has 0.5, then they run at 30fps and so on.

Link to comment
Share on other sites

43 minutes ago, Exca said:

At least on my projects I have no problems. Though I don't use the shared ticker. I create a new one and run everything based on that. But I don't see how running with shared vs. running with own could break animatedSprite.

No matter the fps the animated sprites are running at the speed I order them to run. I keep tickers target fps at 60 so deltatimes are around 1 when game is running 60fps, 0.5 when running 120fps and so on. Then in the updateloop I give the delta to update loop and if it has 1 as it's speed then animations run 60fps, if it has 0.5, then they run at 30fps and so on.

How do you target an FPS?- Well... I guess you're using you're own custom ticker... but yeah, the above code on my original post is literally copied straight from my game. So if I was supposed to do something additional then I likely didn't.

Actually, it sounds like on your custom code you've done something additional that I haven't and that I don't know to do that's letting your animations work properly. Is there an example of how to code this properly so frames are limited and animations are smooth?

Link to comment
Share on other sites

var app = new PIXI.Application();
document.body.appendChild(app.view);

PIXI.loader
    .add('required/assets/basics/fighter.json')
    .load(onAssetsLoaded);

function onAssetsLoaded()
{
    // create an array of textures from an image path
    var frames = [];

    for (var i = 0; i < 30; i++) {
        var val = i < 10 ? '0' + i : i;

        // magically works since the spritesheet was loaded with the pixi loader
        frames.push(PIXI.Texture.fromFrame('rollSequence00' + val + '.png'));
    }

    // create an AnimatedSprite (brings back memories from the days of Flash, right ?)
    var anim = new PIXI.extras.AnimatedSprite(frames, false);

    /*
     * An AnimatedSprite inherits all the properties of a PIXI sprite
     * so you can change its position, its anchor, mask it, etc
     */
    anim.x = app.screen.width / 2;
    anim.y = app.screen.height / 2;
    anim.anchor.set(0.5);
    anim.animationSpeed = 10/60;
    anim.play();

    app.stage.addChild(anim);

    // Animate the rotation
    app.ticker.add(function(d) {
        anim.rotation += 0.01;
        anim.update(d);
    });
}

This one's based on the spritesheet example. Target fps is 10.

If on the other hand you want all rendering to be done on 10fps,  you need a custom solution. I would not recommend that though as it will induce a lot of timing problems when animation frames are not triggered exactly when wanted.

On the other hand setting animations with wanted fps allowes them to play how intended and everything else stays smooth, for example the rotation of plane in the example. And you get to keep the fps that browser is intending.

Link to comment
Share on other sites

2 hours ago, Exca said:

var app = new PIXI.Application();
document.body.appendChild(app.view);

PIXI.loader
    .add('required/assets/basics/fighter.json')
    .load(onAssetsLoaded);

function onAssetsLoaded()
{
    // create an array of textures from an image path
    var frames = [];

    for (var i = 0; i < 30; i++) {
        var val = i < 10 ? '0' + i : i;

        // magically works since the spritesheet was loaded with the pixi loader
        frames.push(PIXI.Texture.fromFrame('rollSequence00' + val + '.png'));
    }

    // create an AnimatedSprite (brings back memories from the days of Flash, right ?)
    var anim = new PIXI.extras.AnimatedSprite(frames, false);

    /*
     * An AnimatedSprite inherits all the properties of a PIXI sprite
     * so you can change its position, its anchor, mask it, etc
     */
    anim.x = app.screen.width / 2;
    anim.y = app.screen.height / 2;
    anim.anchor.set(0.5);
    anim.animationSpeed = 10/60;
    anim.play();

    app.stage.addChild(anim);

    // Animate the rotation
    app.ticker.add(function(d) {
        anim.rotation += 0.01;
        anim.update(d);
    });
}

This one's based on the spritesheet example. Target fps is 10.

If on the other hand you want all rendering to be done on 10fps,  you need a custom solution. I would not recommend that though as it will induce a lot of timing problems when animation frames are not triggered exactly when wanted.

On the other hand setting animations with wanted fps allowes them to play how intended and everything else stays smooth, for example the rotation of plane in the example. And you get to keep the fps that browser is intending.

So I actually wasn't previously using .update() for my animation and setting autoupdate to false in the animated sprite. I tried implementing what you've written here into my code, sadly to my disappointment, it didn't change the behavior at all. It's still skipping frames and not running smoothly at all. Let me post some relevant snippets from my code ?

Something I thought I'd also mention. I'm running PIXI 4.3.4  Not sure if that has anything to do with it though

//Frames are added first then the animated sprite and it's properties are created below.

player = new PIXI.extras.AnimatedSprite(frames, false);

player.name = "player";
player.circular = true;
player.anchor.set(0.5,0.5);
player.position.x = 350;
player.position.y = 1130;
player.animationSpeed = 12/60;
player.play();


//The renderer will update the player sprite so long as we're in the play state.
renderer.ticker.add(function(delta){
deltaGlobal = delta;
if(state==play){
player.update(delta);
}
state();
});


if you'd like to see the full code, you can see the attached file below, or download the current build from my github page. https://github.com/bryanwillis7/faerieFM

main.js

Link to comment
Share on other sites

I haven't used animatedSprite yet personally but it seems to have everything you need to run your animation on time based. 

Making everything time based is fairly simple but note that when you get very low FPS (and I mean global FPS here) then your time based animation will become shoppy, still accurate but shoppy. Also most if not all tween engines are time based.

basic idea is: value / T (miliseconds) = total value per miliseconds

myibject.x = (value / T) * currentT (in this case currentT is how much time has passed since the animation started but this can be adjusted from the last update as well)

Link to comment
Share on other sites

14 hours ago, forleafe said:

Something I thought I'd also mention. I'm running PIXI 4.3.4  Not sure if that has anything to do with it though

Can you try with the newest pixi version just to rule out that it's not related to pixi version?

Link to comment
Share on other sites

4 hours ago, Exca said:

Can you try with the newest pixi version just to rule out that it's not related to pixi version?

Tried on the latest version of pixi 4.8 and it made no difference. Guess I'm gonna have to build my own time based animation code.  @botmaster Going to have to look more closely at your code, because at a glance it didn't really make any sense.

Value/T = total value per miliseconds.  - Value? Value of what? What's this function trying to give me?

 

Link to comment
Share on other sites

17 minutes ago, Exca said:

Found the issue.

Change your main container from ParticleContainer to regular Container. ParticleContainer should only be used for particles.

Yep. Spot on! That fixed it. Thank you so much.

okay so this begs a few questions.

1) What exactly are particles and when is a good time to use them?

2) Why would a particle container prevent animations from running smoothly? I thought the very purpose of them was too offload rendering to the gpu or some thing like that.. so I can render more sprites on screen at once.

Link to comment
Share on other sites

Particles in general are sprites that you want to display more than thousands. They are usually used in effects like explosions, rain, etc.

ParticleContainer in pixijs is a special type of container that is optimized to display thousands of sprites. This is done by removing lot of features normal containers have. For example by default ParticleContainers do not have alpha enabled. They also block texture changes (which is required by animatedSprite to work properly) by default and tinting just to name a few.

ParticleContainers are made purely for speed and you should only use them when you know that the amount of sprites is constraining the performance. I have a project where I have about 3500 particles and I'm not using particlecontainer for those as regular container can handle that amount easily. On one other project I have 10k, and in those numbers the performance change starts to be visible.

Link to comment
Share on other sites

2 minutes ago, Exca said:

Particles in general are sprites that you want to display more than thousands. They are usually used in effects like explosions, rain, etc.

ParticleContainer in pixijs is a special type of container that is optimized to display thousands of sprites. This is done by removing lot of features normal containers have. For example by default ParticleContainers do not have alpha enabled. They also block texture changes (which is required by animatedSprite to work properly) by default and tinting just to name a few.

ParticleContainers are made purely for speed and you should only use them when you know that the amount of sprites is constraining the performance. I have a project where I have about 3500 particles and I'm not using particlecontainer for those as regular container can handle that amount easily. On one other project I have 10k, and in those numbers the performance change starts to be visible.

Okay I have to ask, What in the world are you doing that needs 10,000 sprites? My focus is primarily 2D animation/art and I can't think of a thing that would need that many sprites. Even 10,000 raindrops would be extremely noisy and distracting I'd think. Don't get me wrong though, I find it fascinating! Thank you so much for your explanation though. I have a much better idea of how the particle container works.

Link to comment
Share on other sites

Mainly for effects, particle trails are great for example when you want to move users view from game area to scoreboard.

Havent got any game screenshots/videos/links to give at this moment. But here's one visual thingie that uses 10 million particles (in webgl2, this cannot be done in webgl1): https://excaa.github.io/random/webgl2_particletest/bin/index.html#10000000

Move your mouse to make the particles move. And change the number in link to increase/decrease number of particles and then reload.

Link to comment
Share on other sites

1 hour ago, forleafe said:

Okay I have to ask, What in the world are you doing that needs 10,000 sprites? My focus is primarily 2D animation/art and I can't think of a thing that would need that many sprites. Even 10,000 raindrops would be extremely noisy and distracting I'd think. Don't get me wrong though, I find it fascinating! Thank you so much for your explanation though. I have a much better idea of how the particle container works.

That type of displaying is often referenced as 'flatten' where all contained objects must be shader compatible and will all be rendered in one draw call.

The code I showed was a pseudo code of course and the 'value' can refer to any numeric amount like the total number of frames of an animation or the total number of pixels to move an object by, or an angle, ect ... 

Frame based animation or motion gives you no control on how long/fast it will take for the animation or motion to complete. A 60 frames animation at 60fps in theory will complete in 1 second but due to framrate fluctuations it's going to be + or - 1 seconds. Even worse if the fps drops to 45 or 30 then your animation will take even longer to complete.

Same for motion, adding +5 to the x property of an object to move it across the screen at each frame/update at 60fps doesn't guaranty the object would have moved 300px in 1 second, it might be close if framerate is consistent or very off if framrate is not.

In time based animation you calculate by how much the initial value must increase based on how much time has passed since last update. For the motion example, the goal is to move by 300px in second which is (300/1000) = 0.3px per millisecond. With each update/tick you calculate how much time (in milliseconds) has passed since last update then you apply:

var passedTime = currentTime - lastTime (in milliseconds, currentTime is the recorder time at this update, lastTime is the recorder time at last update)

var valuepermillisecond = (300/1000) < this really should be dynamic and not hard coded values

myobject.x += passedTime * valuepermillisecond

// we move our object according to the time that has passed. In this case the object will have moved 300px in one second regardless of framerate.

 

Now when dealing with frame animation the idea is the same but you must of course roundup the numbers since in time based you only deal with float. In that case that would be:

var valuepermillisecond = (total number of frames/1000)

myobject.gotoAndStop(Math.floor(valuepermillisecond))

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

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