PDA

View Full Version : Getting a perfect time slice


Raptisoft
05-07-2006, 04:04 AM
Hi all,

I seem to be having a mentally deficient day... I am unable to come up with a sensible algorithm to accomplish something, even though it should be fairly straightforward.

I want to draw my screen at about 60 FPS-- for round numbers, let's just say I want to draw every 16 ms.

When I draw, I want to give myself a floating point variable indicating how far off the draw is-- for instance, if I was drawing 8 seconds early, that variable would be .5... if I was drawing 8 seconds late, it'd be 1.5. If I was drawing 16 seconds late, it'd be 2.0.

I want to use this to move something perfectly smoothly (right now I use an updates/sec method like the Popcap framework). So whenever I draw, I'd say, like, move left (3 pixels * timeslice of draw).

Anyone offer any hits? I think I'm on the wrong end of my technical/artistic cycle, because this seems like a really easy problem to me.

Glen Pawley
05-07-2006, 05:07 AM
Hi all,

I seem to be having a mentally deficient day... I am unable to come up with a sensible algorithm to accomplish something, even though it should be fairly straightforward.

I want to draw my screen at about 60 FPS-- for round numbers, let's just say I want to draw every 16 ms.

When I draw, I want to give myself a floating point variable indicating how far off the draw is-- for instance, if I was drawing 8 seconds early, that variable would be .5... if I was drawing 8 seconds late, it'd be 1.5. If I was drawing 16 seconds late, it'd be 2.0.

I want to use this to move something perfectly smoothly (right now I use an updates/sec method like the Popcap framework). So whenever I draw, I'd say, like, move left (3 pixels * timeslice of draw).

Anyone offer any hits? I think I'm on the wrong end of my technical/artistic cycle, because this seems like a really easy problem to me.

What is the 'updates/sec' method?

I've never really researched the 'correct' way to move objects smoothly, but this is how I do it. I dislike any method which looks at the current frame rendering time because those techniques are always so sensitive to rounding errors. What I do is I timestamp the start of events. For example, let's say that that object X starting moving at time 0, and it should reach it's target at time 1000. Whenever my draw functione executes, it looks at the current time and draws the object at the relative position. So when it executes at time 100, the object is drawn 0.1 along the way. At time 116, its drawn .116 along the way.

1) Duration of frame becomes irrelevant.
2) Events are synchronized.
3) It's as smooth as possible.

Or am I saying the obvious? :o

Mike Wiering
05-07-2006, 05:19 AM
Anyone offer any hits? I think I'm on the wrong end of my technical/artistic cycle, because this seems like a really easy problem to me.

Something like this?

FPS = 60
T = (1000/FPS)

t = ms()
lag = (t - last) - T
last = t
return lag / T

You'll need an accurate ms() function (unlike gettickcount), you could probably use rdtsc or QueryPerformanceCounter().

PeterM
05-07-2006, 06:52 AM
Sounds like everything you need to know is here:
http://www.gaffer.org/articles/

Have a read through the first couple of articles - it won't take long, but will "change your life" as it were! ;)

Hope this helps,
Pete

jefferytitan
05-07-2006, 04:13 PM
So you're effectively doing a straight-forward interpolation between keyframes, i.e. it's velocity changed at time a, and we just interpolate from that point using the original location, time elapsed and velocity. Seems sensible to me. Other methods may get cumulative rounding errors. Always a bad look.

What is the 'updates/sec' method?

I've never really researched the 'correct' way to move objects smoothly, but this is how I do it. I dislike any method which looks at the current frame rendering time because those techniques are always so sensitive to rounding errors. What I do is I timestamp the start of events. For example, let's say that that object X starting moving at time 0, and it should reach it's target at time 1000. Whenever my draw functione executes, it looks at the current time and draws the object at the relative position. So when it executes at time 100, the object is drawn 0.1 along the way. At time 116, its drawn .116 along the way.

1) Duration of frame becomes irrelevant.
2) Events are synchronized.
3) It's as smooth as possible.

Or am I saying the obvious? :o

Phil Steinmeyer
05-08-2006, 07:51 AM
The thing to be wary of when using variable sized time-slices is acceleration/gravity.

If an object is moving at a fixed, unchanging speed, then simple interpolation is fine.

But if an object is subject to acceleration/gravity, then you will get different results with different sized time slices (i.e. there's no easy mathematical way to interpolate uniformly across different sized time slices).

Three ways to address this:

1) Ignore it - within reasonable time slices (say 16-33 ms), the effect may be minor, and for stuff like particles, precise positioning isn't so important anyways.
2) Force constant-sized 'Large' time slices. Run your internal update loop at, say 100 hertz regardless of frame rate. If a given frame takes 16 ms, then you will run your 'update' code either once or twice, depending on what the timeslice 'remainder' from the previous run was. The downside is that in some cases this may cause movement to look a little jittery (i.e. when your update loop is at 100 herts/fps, and your frame rate is 60, you might be able to see the stutter).
3) Force constant-sized, 'Small' time slices. Same as #2, but run the update loop 250 times per second or so (i.e. once every 4 ms). This pretty much eliminates the jitter, but may cost performance if your update routine is complicated/time consuming.

#2 and #3 assume your 'Update' loop is separate from your 'Draw' loop.

PeterM
05-08-2006, 07:55 AM
I would recommend approach #2 and to interpolate your positions when rendering. It's explained pretty well in the Gaffer articles.

This approach gives stability of a fixed update rate and eye-candy of a maximal rendering rate.

Mike Wiering
05-08-2006, 02:39 PM
I would recommend approach #2 and to interpolate your positions when rendering. It's explained pretty well in the Gaffer articles. That normally works fine, but be aware that this can make objects appear to "take shortcuts" if they go fast enough. For example, if you have an object rotating fast around another object, it might sometimes be in the middle of that other object.

Pyabo
05-08-2006, 07:19 PM
But if an object is subject to acceleration/gravity, then you will get different results with different sized time slices (i.e. there's no easy mathematical way to interpolate uniformly across different sized time slices).


I beg to differ... I learned a pretty easy formula for this in my highschool physics class. :)

PeterM
05-08-2006, 07:34 PM
Do you mind sharing?

Savant
05-09-2006, 04:31 AM
Seriously. Some of us are further away from high school than others.

Sol_HSA
05-09-2006, 05:04 AM
An easy way is not to use variable time slices.. I've written a tutorial chapter on this, at http://iki.fi/sol/gp/ch09.html

Jamie W
05-09-2006, 08:36 AM
I've been thinking about this, and I'd really like to get some feedback (esp. what the drawbacks are) for this solution:

Have 2 functions:
Game_MoveStuff()
Game_DrawStuff()

The Game_MoveStuff() function will update (move) everything 1ms (1/1000th of a second).

The game loop will look something like:

1. Read current game time (before jumping in to the game loop).
2. Game_DrawStuff()
3. Flip screen.
4. Read current game time.
5. n = difference between now and last update (in ms).
6. Repeat <n> times:- Game_MoveStuff()
7. Go back to 2.


As I see it:

FOR: You only need to update game objects by a fixed unit of time (1ms).

AGAINST: Have to process all game objects 16-12 times each frame update (dependent on monitor refresh rate).



With processing power as it is today, I'm not sure that moving all game objects (computing x,y and animation frame etc) would take that much time anyway.

Things like collision you could do every 10 iterations of the Game_MoveStuff() function.

Also, computing the animation frame to display, would only need to be done once per frame update.

I really like the idea of not moving game objects a variable amount, and using floats for x and y etc.

Any thoughts?

EDIT:

Ah, just read Phil Steinmeyer's post above. What I'm suggesting is the same as his option #3, but with even smaller updates (1ms, and not 4ms).

Pyabo
05-09-2006, 12:11 PM
Seriously. Some of us are further away from high school than others.

Hey, it's been a while for me too! Fourteen years to be exact. I just remembered that I *learned* the formula, not what is actually was. :)

But here it is:

d = v*t + 1/2 * a * t^2

That is, displacement equals initial velocity multiplied by time, plus one half accelelration multiplied by time squared. Here's a little primer (http://www.glenbrook.k12.il.us/gbssci/phys/Class/1DKin/U1L6a.html) I found.

This of course assumes constant acceleration.