Log in

View Full Version : The Arkanoid Jitters


BrewKnowC
05-31-2004, 05:19 PM
Hi, After playing a few of the new arkanoid clones that have been posted on this board I caught the arkanoid fever and started to make a freeware clone. Everything is going smooth except the ball has a stutter. I thought it might be my timing system so I converted the whole game loop over to a fixed time logic loop which renders as much as possible. This helped with the "shadow ball" but still the ball stutters as if its not maintaining a constant pixel speed. Has anyone run into this problem before? I'm running the logic at 60 fps and the rendering is keeping up. The refresh rate is 60Hz 800x600x16 DX6.1. I thought the stutter was a by-product of moving that ball at faster speeds, but I noticed it doesn't happen on "Bricks of Egypt" or "Ricochet". Oh and the ball is using floats for x,y,vx,vy. Thanks

radiance
05-31-2004, 06:18 PM
I can't help with Windows specific stuff but I have faced this issue a number of times. A few things you can look at:

Is every frame exactly the same time? Even a relatively tiny variance can be noticeable. Also, if you're drawing multiple times per refresh and the multiple isn't a factor of the refresh rate then maybe you're drawing 4 frames one refresh, 3 frames the next, 4 the next, etc. Then again, with this method only the last drawing would be visible, so if it doesn't occur at the same time relative to the next refresh every time then you'll get stuttering.

Are you really drawing at fractional points? Possibly you are keeping track of the location with floating point, but when the ball gets drawn the location is rounded off.

Is it possible that at times the ball is being drawn near the same place as the monitor's electron beam? If one frame it's being drawn before the beam and the next it's drawn after then you could see stuttering.

I think the two main solutions are to draw many times the refresh rate (maybe 300 Hz?), or to match the refresh rate exactly.

Hope that made sense.

serg3d
05-31-2004, 10:39 PM
or use physical timing.
Calulate position X1 = X0 + V*deltaTime, where deltaTime is time spent on the rendering of the previous frame. deltaTime = timeCurrent-timePrevious .

Nemesis
05-31-2004, 11:52 PM
In your case I would strongly recommend switching to fixed frame-rate and using frame-based (rather than time-based) velocities.

I think physical timing is best suited for 3D.

princec
06-01-2004, 01:32 AM
You may find that using floats to represent coordinates and velocities is responsible. Stick to ints and fixed point.

Cas :)

KoekTromL
06-01-2004, 02:37 AM
I had major hickups when 'stuff' was running in the background (like FindFast, Virus checkers, etc).

It could also be some audio engine thread doing a large part of the mixing just before you switch pages, possible causing it too miss some flips (less likely though).

I used floats before and it doesn't really matter. Make sure you do a round on it, not just an int conversion!

Are you using a page-flipping structure and actually blitting to the backbuffer?

If your gameloop looks like this (or other time-related variants).
void OnTimer60Hz()
{
Render();
}
You are bound to get a stutter.

One way to get your ball "smooth as" is:
const uint cuiRefreshRate = DetermineRefreshRate();
while ( true ) {
Coordinates += SpeedThatVariesWithRefreshRate;
Render();
Flip( DD_WAIT );
}

SetClassPriority( High ) is another interesting one to look at.

When can I play it. ;)

BrewKnowC
06-01-2004, 08:40 AM
Thanks everyone for all the good suggestions...

@radiance - interesting... could you explain how I would go about getting the timing EXACTLY the same for each frame? Thanks

@Nemesis & Princec - My original engine used ints for x,y and fixed frame rate and the stutter was much worse with a definite "double ball" look to it.

@serge3D & KoekTromL - I am doing double buffered page flipping. I think both of your suggestions come down to the same idea: varying the ball speed based on the dynamic frame speed. I think both of you are probably right and this is the next thing I'll try when I get home from work. KoekTromL - I am just doing a float -> int conversion... I'll make sure I do a round instead.

radiance
06-01-2004, 06:01 PM
Originally posted by BrewKnowC
@radiance - interesting... could you explain how I would go about getting the timing EXACTLY the same for each frame? Thanks


Ah, well that's the tricky part. All I was saying is that I didn't think you were really getting exactly the same time for each frame.

Ideally you just need to know he refresh rate of your monitor and try to draw one frame each refresh.

For example, what I do (using OpenGL and OS X) is either tell OpenGL that I want to sync to the VBL and basically let OpenGL handle it, or I run my screen update function in a timed loop that runs at the same rate as the refresh.

The second one works well most of the time, but you'll get some tearing or jerkyness at the times when the monitor electron beam happens to be crossing your ball at the moment it's being drawn. This might be overkill, but what I've been doing is running my screen update at a slightly faster rate than the refresh and checking the position of the electron beam each time. If it's near the position of my main focal point (your ball in this case) then I delay drawing for a few milliseconds.

I know, I know. It seems bizarrely difficult to get an object, especially a small one, to move smoothly across the screen.

KoekTromL
06-01-2004, 06:31 PM
Originally posted by radiance

I know, I know. It seems bizarrely difficult to get an object, especially a small one, to move smoothly across the screen.

Difficult? That's the easy bit! ;) The difficult bit is when you have to start doing pixel-perfect intersections with varying refresh rates and you don't know how big the next jump is. Aargh! Then try and move something in a sinus pattern with varying refresh rates. Aargh!

:)

It is well worth the effort though!

BarrySlisk
06-01-2004, 09:21 PM
It's probably your timer. Don't use GetTickCount (did you use C++)?
Use the highperformance timer if possible.

BrewKnowC
06-02-2004, 04:22 AM
Originally posted by BarrySlisk
It's probably your timer. Don't use GetTickCount (did you use C++)?
Use the highperformance timer if possible.

You are right... its definitely something with the timer. The more I mess with the timing code, the smoother (or more stuttered) the ball gets. I just have not found the right formula yet. I am using C++. I was using GetTickCount(), then switched to timeGetTime(), and was going to switch to the performance count, but I heard they are not reliable on all systems. I'm still tinkering with it and hopefully I'll have the ball flying smoothly soon. Any other suggestions are welcome.

KoekTromL
06-02-2004, 12:53 PM
I remember reading about this and I think BarrySlisk is right!

If I remember correctly, some people use timeBeginPeriod to increase the resolution to get more accurate/consistent timing intervals, just before they use timeGetTime. You need to call timeEndPeriod afterwards to reset the timer resolution again.

You may also want to read up on QueryPerformanceCounter, that was mentioned a lot as well in that context.

Nemesis
06-02-2004, 01:37 PM
Handy code snippet:


inline double GetTime(void)
{
__int64 currentTime;
__int64 frequency;
QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
QueryPerformanceCounter((LARGE_INTEGER*)& currentTime);
return (double)currentTime / (double)frequency;
};

BrewKnowC
06-02-2004, 01:55 PM
Sorry if this sounds ignorant, but is there a way to get smooth consistent timing without getting deep inside my sprite movement code (without changing the deltas for x and y)? In other words... is there a way to just change the timing code to get nearly perfect timing (consistant in respect to the refresh rate)? This seems like such a simple problem and its giving me so much trouble. :confused:

Thanks

oNyx
06-02-2004, 03:28 PM
Well, it isn't that complicated. Really.

Get the time interval from the previous frame till now (the time wich passed by from one frame to another).

All speeds are stored as units per second.

And you calculate the movement just by multiplying the time fraction with units per second. Eg if units per second is 100 and the time fraction is 0.1 (uh 10fps) you move that object 10 units (eg pixels).

>Make sure you do a round on it, not just an int conversion!

Whoops! Hadn't done that :o

But then again... it was just a horrible inefficient 4k game.

I'll keep it in mind if I ever need that kind of stuff again.

Grimreaper
06-03-2004, 09:39 AM
Use QueryPerformanceCounter - IIRC Nvidia had a cmd-line app with a comparism of different timing mechanisms.

I have found that decoupling the simulation from the rendering to be a good idea. The simulation (in your case the ball) would run at a fixed time step, say 10Hz or whatever, and the graphics code to render as fast as pos. The graphics code just asks the simulation for the current ball position and render it. This solution might be overkill for your game but I have found it very useful and eases debugging.

grimreaper

BarrySlisk
06-03-2004, 11:19 AM
I have some messy code for you:



LONGLONG m_ThisPerformanceTick;
LONGLONG m_LastPerformanceTick;
LONGLONG m_PerformanceCounterFreq;
bool m_bHasPerformanceTimer;
int m_iTicksPerSecond;
LONGLONG m_iPerformanceElapsedTime=0;
int m_iElapsedTime = 0;

bool HasHighPerformanceCounter()
{
m_iLastFrameTime = timeGetTime();
m_iCurrentFrameTime = m_iLastFrameTime;

if (QueryPerformanceFrequency((LARGE_INTEGER *) &m_PerformanceCounterFreq))
{
m_bHasPerformanceTimer = true;

//get current time
QueryPerformanceCounter((LARGE_INTEGER *) &m_ThisPerformanceTick);

m_LastPerformanceTick = m_ThisPerformanceTick;

return true;
}
else {
//init backup timer
}
return false;
}

void UpdateTime()
{
//Update Performance timer
if (m_bHasPerformanceTimer)
{
m_LastPerformanceTick = m_ThisPerformanceTick;
QueryPerformanceCounter((LARGE_INTEGER *) &m_ThisPerformanceTick);
m_iPerformanceElapsedTime = (m_ThisPerformanceTick - m_LastPerformanceTick);

m_fElapsedSeconds = ((float)m_iPerformanceElapsedTime/(float)m_PerformanceCounterFreq);

m_iElapsedTime = (int)(m_fElapsedSeconds * 1000.0);


}
else
{
//update backup timer. timeGetTime() for example.
}

}


If some object moves at 100 pixels pr. second, just do this:


PositionX += 100.0 * m_fElapsedSeconds;

BrewKnowC
06-03-2004, 06:07 PM
Thanks Everyone. I decided to dive in and use the frame independant approach (x = vx*timestep) and it seems to be working the smoothest out of all the other methods I've tried. This turned out to be a very informational thread! Gotta love these boards!

P.S. - Barry, nice backup timer approach!

Thanks Again!

Nemesis
06-04-2004, 12:16 AM
Originally posted by Grimreaper
I have found that decoupling the simulation from the rendering to be a good idea. The simulation (in your case the ball) would run at a fixed time step, say 10Hz or whatever, and the graphics code to render as fast as pos. The graphics code just asks the simulation for the current ball position and render it. This solution might be overkill for your game but I have found it very useful and eases debugging.

grimreaper

I've had the same suggestion from the techie in my team but I was sceptical about having multiple threads due to issues to data synchronicity i.e. I'm using timestep-modulated physics. As a precaution I impose an upperbound to the timestep (e.g. <= 4ms) i.e. if the frame rate really slows down even the physics slows down at a certain critical level. This was to ensure I don't have large jumps caused by huge timesteps i.e. missed collisions etc.

Grimreaper
06-04-2004, 09:54 AM
Originally posted by Nemesis
I've had the same suggestion from the techie in my team but I was sceptical about having multiple threads due to issues to data synchronicity i.e. I'm using timestep-modulated physics. As a precaution I impose an upperbound to the timestep (e.g. <= 4ms) i.e. if the frame rate really slows down even the physics slows down at a certain critical level. This was to ensure I don't have large jumps caused by huge timesteps i.e. missed collisions etc.

It all depends on the game: if the game is relatively complex you still need a low-priority thread to load resources such as textures, level data. You'll also probably need another thread for the music/sound. Not to mention the multiplayer bits - networking definetly requires it's own thread.

Why are you afraid of data synchronization issues? As long as the simulation exposes an interface through which everything must go through you shouldnt get any trouble.

Having said all that - for simpler games it might just be easier to stick everything in one thread.

grimreaper

Nemesis
06-04-2004, 01:42 PM
I'd be more daring with Java or C# but with C++ I tend to think twice or thrice before doing anything of the sort :)

PalmTree
06-04-2004, 10:22 PM
I get tired of this one, but one more time:

NEVER USE QUERYPERFORMANCECOUNTER and friends.

It generates lumpy granular time samples on some hardware under some conditions. I never did figure out what they were, but I've seen it more than once on differing machines and o/s's over the years.

Just use GetTickCount(). I'm 95% certain that this function ends up reading the high-res timer eventually as will all the other variants, so it won't solve the problem. What it will do is give you cleaner code with no room for bugs in your time getting routines.

What will solve your problem is either moving objects by time (as mentioned before). If an object can possibly move a long way due to high speeds, do this:

1 Init a global to zero
2 Each frame before you draw, read the last frame period and add it to this global
3 Drop into a loop:
while (global>=10)
{
Move all my stuff by 10ms worth
Collision detect it all and resolve
global-=10;
}
4 Optional last step of
if (global>0)
{
Move all my stuff by "global" worth
global=0
}

Miss out step 4 and choose the period (the 10) wisely and you can do away with time dependent movement code, though it's no great harm to always work this way imo - it doesn't add a lot of complication at all and there are fringe benefits.

oNyx
06-04-2004, 11:31 PM
>Just use GetTickCount().[...]What it will
>do is give you cleaner code with no
>room for bugs in your time getting
>routines.

No. Not really. The resolution is pretty low and in addition it varies on the different windows versions. On 2k/xp it's 10msec and on 9x/me it's 50-55 msec (duh). You need alot of weird tricks to work around that. There is no way that this bunch of dirty hacks result in cleaner code.

I had to use that kind of crap timer for awhile and it's really no fun at all.

Usefull article:
http://www.gamedev.net/reference/articles/article2086.asp

PalmTree
06-04-2004, 11:40 PM
Scary stuff. All I can say is that GetTickCount() works for me. It must keep an accurate figure even if it's granularity returned is 10ms or so as I've never had a problem with it and never run my games over 100fps anyway.

Now you've piqued my interest I'm gonna investigate some more, but the words "mountain" and "molehill" spring to mind.

When we first encountered the problems using QPC, I stuffed in a call to GetTickCount() instead and all of a sudden the game ran smooth even at a high frame rate. What can I say.

Nemesis
06-05-2004, 02:17 AM
This i the first time I hear (well see written!) that QueryPerformanceCounter() isn't the best timing routine. I think I'll stick to it for now :)

PalmTree
06-05-2004, 07:41 AM
Well, arguments over GetTickCount() notwithstanding, QPC is about the worst of the bunch as far as potentially bad timing is concerned. The effect I saw in person had a granularity of a couple of seconds!

Grimreaper
06-05-2004, 08:45 AM
Originally posted by PalmTree
Well, arguments over GetTickCount() notwithstanding, QPC is about the worst of the bunch as far as potentially bad timing is concerned. The effect I saw in person had a granularity of a couple of seconds!

In all the years I've used QPC I've never had the issues you descibe.

A better source of timing related info is this application from Nvidia: http://developer.nvidia.com/object/timer_function_performance.html. It comes with sources.

On initialization my timer code tries the above timing methods and chooses the best one.

grimreaper

PalmTree
06-05-2004, 08:52 AM
I might switch over to this too since someones kindly bothered to supply source.

I'm not surprised you've never seen this before, but that doesn't mean it isn't widespread enough to be a real problem, which is why I'm always telling people not to touch it and why people write big routines like the avove, I guess.

It doesn't seem to be based on any particular feature such as whether you have O/S x, card x, joystick x or whatever. It shows up on a small percentage of random machines and if you've never suffered a bad one then cool, but it doesn't mean this issue isn't there.

It's not the sort of thing you'll hear about via support calls either. If your game is jittery and crap due to this problem, punters will just write off your demo and try something else...

(btw the "you" in this means "anybody", not you personally).

BarrySlisk
06-05-2004, 09:01 AM
I've heard that timeGetTime() is better than GetTickCount(), but who knows.

I had problems with one of them once. My objects would move jerky, just like org poster described. QPC helped me produce smooth movement. I know that certain motherboards have faulty implementations of QPC (or so I've read on GameDev), but I still believe that it is the best overall solution.

Grimreaper
06-05-2004, 09:03 AM
Originally posted by PalmTree
I might switch over to this too since someones kindly bothered to supply source.

I'm not surprised you've never seen this before, but that doesn't mean it isn't widespread enough to be a real problem, which is why I'm always telling people not to touch it and why people write big routines like the avove, I guess.

It's used in commercial code at the company I work. It's been distributed to thousands of customers. Trust me - it would show up.

The "big" routine above demonstrates common sense and safe programming practice: the guy put in a backup timer just in case QPC is not present, or whatever.

In my code I do something similiar: when I initialize the timer class I check all the timers currently available and run a modified version of the Nvidia code and choose the fastest one. If QPC is not present, it will not of course be used.

One difference I have in my code when using QPC is that on multiprocessor machines I set the thread affinity that the timer is running on as QPC might give different results due to bugs in the BIOS or HAL. Check out the MSDN for details.

grimreaper

BarrySlisk
06-05-2004, 09:09 AM
Originally posted by Grimreaper
[B]It all depends on the game: if the game is relatively complex you still need a low-priority thread to load resources such as textures, level data.

No not really. Unless you need to load new levels or sections while playing (huge areas).

Originally posted by Grimreaper
You'll also probably need another thread for the music/sound.

Isn't that done by DirectSound (or whatever API you are using)?

Originally posted by Grimreaper
Not to mention the multiplayer bits - networking definetly requires it's own thread.

No not really. My game in progress (never to be finished project) does not use threads at all, except those DX creates internally.
No networkthread either. Seems to work ok.

oNyx
06-05-2004, 09:21 AM
>I know that certain motherboards have faulty implementations of QPC

The question is: are they still around?

My guess is that these mobos disappeared several years ago - just because it's a shamefull silly error wich you just won't let happen ever again.

Mainboards are build to last about 5 years and after about 6 years they usually die (resistors doesn't last longer) and if not it's a really crappy machine unable to run any games (my router for example is one of those - it's a Pentium 200).

So PalmTree do you remember the specs of the machine, were you've seen that weird behaviour? Maybe that can give us a little clue :)

PalmTree
06-05-2004, 09:24 AM
It's used in commercial code at the company I work. It's been distributed to thousands of customers. Trust me - it would show up.
Well, I could say that GetTickCount is in at least 3 commercial games I've been invoved in that have sold literally millions between them, but then I'd just be going over old ground yet again as I started out by saying.

I've given my advice. Ignore it if you wish.

Grimreaper
06-05-2004, 09:28 AM
Originally posted by BarrySlisk
No not really. Unless you need to load new levels or sections while playing (huge areas).

I was talking about larger games as I stated in the beginning. Even so, somethings should be loaded as needed - music is a case in point.

Originally posted by BarrySlisk
Isn't that done by DirectSound (or whatever API you are using)?

I dont suppose you keep all the music loaded in ram do you? And multiplexing it with the rest of the code might lead to buffer underflows. Leaving music in its own thread is nice and safe.

Originally posted by BarrySlisk
No not really. My game in progress (never to be finished project) does not use threads at all, except those DX creates internally.
No networkthread either. Seems to work ok.
You dont give enough information about your project for me to comment on it.

Is your project an FPS or an RTS? In an FPS network latency is critical, you dont want to add to it. In an RTS, my "current" project, the latency can be hidden due to the gameplay style of the genre so it could be put all in one thread.

grimreaper

nquijano
06-05-2004, 09:29 AM
Speed step CPU powered laptops are the worst offenders, and still offending : they muck up two of the 3 solutions for timing on windows, and there is nothing really to be done about it according to quite a few very reputable engineers.
iirc, the two finer grained solutions suffer from problems with portables, and it's where you can see a granulairty of a few seconds...
Don't take my word for it, as I ain't a specialist of the topic : posts on gamedev algo and gamedev windows have addressed the issue many times over the past couple years

PalmTree
06-05-2004, 09:31 AM
So PalmTree do you remember the specs of the machine, were you've seen that weird behaviour? Maybe that can give us a little clue I've seen it serveral times over the years, though none real recently but then again I've only seen the same single machine for the last four years, upgrades notwithstanding. :)

The only particular specs I remember was a Win95 Intel machine (about a 200 or so) and a different Win2K machine (about an 800 or so). The Win2K thing had an AGP graphics card, the former didn't. That's about the limit of my memory tbh - I only remember these as they're so starkly different it stuck in my mind as a possibly major problem.

You could well have a point about this bug evaporating with time, like the old pentium divide thing. I sure hope so, but once burnt....

oNyx
06-05-2004, 09:38 AM
Found some details:
http://support.microsoft.com/default.aspx?scid=kb;en-us;Q274323

There is also the source for a console application (on the bottom of the page), wich reports leaps in the performance counter value if they occur.

@PalmTree

Thanks, but an "800 or so"... hadn't expected that :/

PalmTree
06-05-2004, 09:44 AM
Don't take my word for it, as I ain't a specialist of the topic Same here - my eyes glazed over at all those acronyms in the code article link someone posted above.

I'm not very low-level these days (after starting out writing eprom-based 'proper' videogames in pure assembler). All I did was see a problem, fixed it by experiment, and have stuck to using the method I've known to be safe ever since.

What I really don't get is the technical arguments people are putting forth about GetTickCount(). I've used this in a number of games ('AAA' commercial and otherwise) and have never seen a problem - all my stuff runs smooth as a babies arse ime, even on machines with bad QPC, so I'm really not interested in the neigh-saying. Results are the only factor and GTC has given me 100%

People could (and have) make exactly the same statement about QPC but the reported errors when it goes wrong are massively more serious than anything that GTC could produce.

</grumpy git mode>

compumatrix
06-05-2004, 12:10 PM
What do you guys use for timing code on OS X?

I have just been using SDL_GetTicks() but I am wonder if this is the source of some jitter I have been getting, but it could be something else. It may just be because every frame isn't the same amount of time, and I need to average timing data somehow or soemthing, or maybe it is a rounding error somewhere... but I was going to start by trying a different timer but haven't been able to get things to work.

EDIT: I got the code i found online to work but it didn't fix my jitter... i will need to investigate the cause.

thanks,
Jon Kuhn