Breakout clone & smooth ball movement & fixed time step loop with varying framerate

Started by
14 comments, last by ddn3 15 years ago
I'm programming a breakout clone and i'm having some unknows regarding random jumps in the animation of the ball. I'm using a fixed time step loop and also do interpolation with the remaining time from every update. I update the ball position as follows: pos = pos + dir*speed*dt; and at render i interpolate the position like so: pos = pos + dir*speed*dt*interpolator. Every now and then i see sudden jumps in ball position and can't really understand why is this happening. Of course it may be from a variety of reasons but i like to think that the code is fairly optimized(using batch rendering and fast collision detection routines using spatial hashing for the broad phase). The application is fairly big (>500kb of code) and i'm wondering if i may be causing a lot of cache misses. So what is the secret of programming a breakout clone with smooth ball animation on a decent processor (2ghz single core) ? :D [Edited by - Deliverance on March 17, 2009 1:15:32 PM]
Advertisement
A little more code would be nice, and from what I am reading why are you recalculating the position during render? Why not do that is the game code?
What is the value of "interpolator"?
Quote:Original post by Hodgman
What is the value of "interpolator"?


It is in the range 0..1 and it is calculated as follows:

while (accumulator >= fixedDt)
{
UpdateGame(fixedDt);
accumulator -= fixedDt;
}

interpolator = accumulator / fixedDt;

Also a little correction. at render time i do:

posToRender = pos + dir*speed*dt*interpolator.

not increment the position and use that modified version in further calculations.
I could be looking at this wrong but all you should need is:

pos += speed*dt

speed: You can eliminate direction by just negating this value whenever it hits a wall

dt: time since last update

Why wouldn't that work for this situation?
Quote:Original post by DarkZlayer
I could be looking at this wrong but all you should need is:

pos += speed*dt

speed: You can eliminate direction by just negating this value whenever it hits a wall

dt: time since last update

Why wouldn't that work for this situation?


I'm separating between the direction and the magnitude of the direction to easily change travelling speed(ex: speed = 2.0). This way i'm not changing the direction which remains constant.
Your equation is fine, unless there is a serious bug in the interpolator, which you should do some simple test to verify its working correctly.

The problem with fixed timesteps is that games rarely go at a fixed timestep. Even with the simplest game, running at 60fps there isn't any guarantee that some blocking processes doesn't hog the CPU causing it to go less than 60fps. When that happens your game will stutter, the human eye is quite sensitive to changes in update rates, more so than the update rate itself. A game going at 15fps consistently is smoother than one going inconsistently at 30fps.

You'll need to take into account when the game stutters for whatever reason and if so update multiple fixed timesteps until you catch up to the realtime passage between the frames. Be sure to keep track of the time remainder to add to the next frame time if there is any. That way your game will try to run realtime even though it is using a fixed timestep. If for whatever reason you can't catch up to realtime, just update as much as u can that frame and try to catchup over time.

Good Luck!

-ddn

I think i have nailed the reason why i see the annoying stuttering on the screen.
First of all here is the fixed time step loop i'm implementing:

void CGameEngine::Update(){														float amount = 1.0f / 400.0f;		static float accumulator = 0.0f;	accumulator += timer.GetTime();	timer.Reset();							        numUpdates = 0;	while (accumulator >= amount)	{		UpdateSimulation(amount);				accumulator -= amount;	                        numUpdates++;        }        interpolator = accumulator / interpolator;}


TESTING ON: Xeon quadcore, 2.1ghz, nvidia geforce 8500 GT

I did some profiling with VSync on and saw that on my system numUpdates is 6 or 7 most of the time. But quite often it burst to a value greater than 10 or 20, let's say 16 or 23. It is very clear that the ball position would be updated proportional to numUpdates.
Now the fps is high enough, without VSync off it is over 2000 FPS.

If i turn VSync off the the choppiness is gone: looking to numUpdates it's says that it is between 0-2 all the time. The choppiness is gone.

Of course i have a constant there: amount = 1/400. How should i choose this value and how should i solve the issue in the case where VSync is off and numUpdates varies often with big amounts? Also the issue with the choppy animation appears with vsync off on a lower spec hardware; this means that i found a good parameter set that works well only on the system mentioned above. What about generality? It seems that the fixed time step loop is not enough here. :D

EDIT: Also the interpolation trick does not have much to say because of the very small constant time step.
Your time function could be to blame, I hear timeGetTime (if your using the win32 function of the same name ) has a accuracy of 1-10 ms! which if your running at 60fps, can give u variance of 6-60% between each frame, stutter time!

You can use the performance counters for higher accuracy but they too have a strange bug where they would return anomalous values occasionally, so you need to verify the values you get back.

See site for overview:

http://www.geisswerks.com/ryan/FAQS/timing.html

Good Luck!

-ddn
Quote:Original post by ddn3
Your time function could be to blame, I hear timeGetTime (if your using the win32 function of the same name ) has a accuracy of 1-10 ms! which if your running at 60fps, can give u variance of 6-60% between each frame, stutter time!

You can use the performance counters for higher accuracy but they too have a strange bug where they would return anomalous values occasionally, so you need to verify the values you get back.

See site for overview:

http://www.geisswerks.com/ryan/FAQS/timing.html

Good Luck!

-ddn


I see, though i'm using sfml for timing and sfml uses internally high precision timers(if available). To be sure i'm using such timers i've written this piece of code:

	{	sf::Clock c;		float a = 0.0f;	c.Reset();	for (int g=0; g<10000000; g++)	{		float d = sqrtf(g);		a += d*d*d;	}	char mess[256];	sprintf(mess, "time=%f a=%f", c.GetElapsedTime(),a);	MessageBox(NULL, mess, mess, MB_OK);	}


The message box proudly says: time=0.269663 a=1274143319414508570.000000 (hope i did copy correctly in case someone tries the code :D ).

So i don't think it's the timer's precision.

[Edited by - Deliverance on March 17, 2009 8:27:58 PM]

This topic is closed to new replies.

Advertisement