Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » time based movements = slow animation

This thread is locked; no one can reply to it. rss feed Print
time based movements = slow animation
Pawel B
Member #5,231
November 2004

I added a timer in the beginning of my render function and at the end. I compute the seconds that have gone by (about 0.02seconds) and used that to multiply the object's velocity. I had to change my velocity number from 5.0 to 360 for the object to go about the same speed as it did without the timer. If I pay attention closely I can see that the animation is choppy but like I said I have to pay attention very closely.

Am I missing something?

Fladimir da Gorf
Member #1,565
October 2001
avatar

The way I do it is to have a target fps like 100 which you intend your game to be run in (and design the speeds such that everything looks fine in 100 fps). Then multiply all the speeds and accelerations by float(TARGET_FPS)/float(currentFps). If the current fps is half of the target fps the objects will move twise as much every frame and so on.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

james_lohr
Member #1,947
February 2002

Quote:

Then multiply all the speeds and accelerations by float(TARGET_FPS)/float(currentFps)

That's just wrong. It's ok to multiply the velocity by this ratio if the velocity is constant, but multiplying the acceleration by this value will screw up the physics.

Fladimir da Gorf
Member #1,565
October 2001
avatar

No it doesn't. Maybe I didn't explain myself well.

That's because float(TARGET_FPS)/float(currentFps) is actually the delta time between frames. And as you know the acceleration is the change in speed per time unit just as the movement is a change in position per time unit. Like:

speed += dt * acceleration;
position += dt * speed;

I've always done it this way and I can say that it works.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Pawel B
Member #5,231
November 2004

Thank you sooo much it works perfectly. Is there anything else I should be doing with timers except moving objects?

Fladimir da Gorf
Member #1,565
October 2001
avatar

Use it everywhere where you have some kind of a speed (rotation speed, fading speed, color changing speed) or acceleration (increase in turn rate, although a very rare occasion).

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

james_lohr
Member #1,947
February 2002

Quote:

speed += dt * acceleration;
position += dt * speed;

Sorry, you're absolutely right.

I was thinking about dampening eg:

speed *= 0.99

...I suppose this isn't a problem either 'cause you can write it as:

speed = speed - speed*(1-0.99);

or:

speed += speed*(0.99-1);

which works fine with what you gave:

speed += dt * speed*(0.99-1);

If fact I don't know what I was thinking of... probably just being an idiot. :-/

Fladimir da Gorf
Member #1,565
October 2001
avatar

Well, I could've said it clearer than this:

Quote:

Then multiply all the speeds and accelerations by float(TARGET_FPS)/float(currentFps).

You could read that as this:

speed *= dt;
acceleration *= dt;

which is wrong, as I mean

speed += dt * acceleration;

and so on.

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Thomas Harte
Member #33
April 2000
avatar

So, to sum up: the original poster was using time deltas calculated exactly from one frame to the next and Fladimir's fix is to use an averaging of those time deltas to avoid the low resolution Allegro timer problems.

Personally I do exactly the same thing, but have found that averaging only over the last three or four frames is sufficient - no need to average over an entire second or whatever (typically longer than 4 frame) period you calculate FPS over.

Jakub Wasilewski
Member #3,653
June 2003
avatar

Quote:

speed += dt * speed*(0.99-1);

This won't work as expected, and will result in more dampening at lower framerates. Examine two possibilities:

1dt = 1
2speed = 100
3 
4speed -= 1, speed = 99 // frame 1
5speed -= 0.99, speed = 98.01 // frame 2
6speed -= 0.98, speed = 97.03 // frame 3
7speed -= 0.97, speed = 96.06 // frame 4
8...
9speed = 60.5 // frame 50
10 
11/******************************************/
12 
13dt = 5
14speed = 100
15
16speed -= 5, speed = 95 // frame 5 from previous example
17speed -= 4.75, speed = 90.25 // frame 10 from previous example
18...
19speed = 59.87 // frame 50 from previous example

When dampening you should use a formula like:

speed *= std::pow(dampeningFactor, dt)

That way, you achieve consistent results regardless of the framerate. The differences in my example may seem small, but at 100 logic frames per second, the difference between particular framerates is noticable.

I ran into this when developing SWB, which uses delta time. Bullets are affected by air friction (constant dampening factor for speed), and stay in the air for 6, 7 seconds. The AI usually missed its mark, about 10 pixels short, when it should be perfect. Why? Because it used lower resolution for bullet prediction (dt = 50ms) than the game itself (dt maintained around 10ms), and because I used a faulty formula without the pow.

I hope that it didn't sound like an "I'm smart, you're not" statement. It's just that I ran into that problem earlier.

[edit]
Oh, and personally, I use a high frequency timer to calculate dt accurately for every frame, instead of relying on FPS.

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

Evert
Member #794
November 2000
avatar

Quote:

speed += dt * acceleration;
position += dt * speed;

Slightly more physically correct would be

position += dt * speed + 0.5 * acceleration * dt*dt;
speed += dt * acceleration;

to take into account that the velocity is not a constant during the integration. The error by neglecting this is O(dt^2), so it is negligible if dt is small enough (and maybe negligible for in general for the purpose of computer games).

Thomas Harte
Member #33
April 2000
avatar

Quote:

Oh, and personally, I use a high frequency timer to calculate dt accurately for every frame, instead of relying on FPS.

This is close to what I do, but I find that high frequency timers are very unreliable in Allegro that relying on anything over about 100bps being portable isn't smart. Hence I average a small number of frames (3 in the thing I'm writing for the ray casting competition) to remove any sudden lurches.

Of course, normally I program in SDL where SDL_GetTicks() does the business for me in a much more predictable fashion and without the processing overhead of an extra thread!

Jakub Wasilewski
Member #3,653
June 2003
avatar

Thomas Harte said:

This is close to what I do, but I find that high frequency timers are very unreliable in Allegro that relying on anything over about 100bps being portable isn't smart.

I don't use Allegro timers ;). The TimeKeeper class uses QueryPerformanceCounter under Windows, and gettimeofday under Unixes (I hope that'll work for Macs too).

Maybe we could implement an interface for those high resolution clocks in Allegro itself? Perhaps al_get_ticks(), al_get_ticks_per_sec()? ;). I think that every platform supported be Allegro provides the interface neccessary to implement that (and if not every platform does, al_get_ticks_per_sec() could return 0).

---------------------------
[ ChristmasHack! | My games ] :::: One CSS to style them all, One Javascript to script them, / One HTML to bring them all and in the browser bind them / In the Land of Fantasy where Standards mean something.

Thomas Harte
Member #33
April 2000
avatar

Quote:

(I hope that'll work for Macs too)

I built and ran the following under OS X v10.4.1, gcc 4.0:

#include <sys/time.h>
...
  int c = 2000;
  while(c--)
  {
    struct timeval t;
    gettimeofday(&t, NULL);
    printf("%d:%d\n", t.tv_sec, t.tv_usec);
  }

And got the output:

Quote:

1116788235:919471
1116788235:919490
1116788235:919503
1116788235:919516
1116788235:919529
1116788235:919542
1116788235:919554
1116788235:919567
1116788235:919580
1116788235:919593
1116788235:919606
1116788235:919619
1116788235:919632
1116788235:919644
1116788235:919657
1116788235:919670
(etc)

So it should be good!

Quote:

Maybe we could implement an interface for those high resolution clocks in Allegro itself?

I would strongly support this, but the traditional line from Allegro developers has been "we don't need that we have timers" and "timers are good enough - the developer should always be making a fixed number of discrete logic steps per second". So I won't hold my breath.

Fladimir da Gorf
Member #1,565
October 2001
avatar

I really don't like it how even the Allegro's docs recommend to limit the frame rate to a specific number. Tell me, how many commercial games do that nowadays? None. Zero. Null. So why would the Allegro developers do that then?

Maybe because Allegro is considered as a newbie library and copy-pasting a few lines from the manual sounds like the best solution, huh? I'd say the delta time syste is, in fact, much easier to understand for new programmers than the strange increasements and decreasements. Most of us have learned some physics, right?

OpenLayer has reached a random SVN version number ;) | Online manual | Installation video!| MSVC projects now possible with cmake | Now alvailable as a Dev-C++ Devpack! (Thanks to Kotori)

Richard Phipps
Member #1,632
November 2001
avatar

Quote:

Most of us have learned some physics, right?

None at all I'm afraid. The existing frame method is good for some games and bad for others, the same as for the delta time system.

Use what works best for each game. :)

Evert
Member #794
November 2000
avatar

Quote:

Maybe we could implement an interface for those high resolution clocks in Allegro itself?

Makes sense, at least for discussion post 4.2.

Quote:

I really don't like it how even the Allegro's docs recommend to limit the frame rate to a specific number. [...] So why would the Allegro developers do that then?

Because they have a lot of things to do and making substantial changes to the docs takes a tremendous amount of time - especially if it's something that can be argued pro and con.
That said, there is no inherent problem with using a fixed logic rate for some types of game. It won't do very well for a 3D first-person shooter, but it's fine for a 2D top-down RPG. The main point is that games need to run at the same speed on all computers. Having a fixed logic rate more or less fixes the frame rate as well, since there is no point in redrawing frames if nothing has changed.

Go to: