Writing

Timers: Part One

Timers:
Part One | Part Two

I've had to learn more about timers than I really wanted to. My testing gave quite confusing results, so I had to dig into the issues and was not very satisfied with the answers. The bottom line is the resolution of Java timers is not very accurate because Java doesn't play well with Windows processor in a multiple processor architecture. Mac and Linux are fine, even with multiple processors, according to many other game programmers. It seems that Windows will sleep processes in different areas of the processor or even in different processors effectively blacking out the timer so Java does not know how much concurrent time has passed. Estimates seem that these blackouts can vary wildly from 2 to 20 milliseconds. This causes both inaccurate FPS reporting and jitters.

100 FPS and the Jitters

My basic millisecond counter counts the number of times the game loop loops in 1000 milliseconds or one second. To display smooth animations and movements, we need movement and frame rate to be constant over time. The easiest example is movement. Lets say I want to move a sprite across the screen 10 pixels every 20 milliseconds. In a perfect world, it would look like this. The velocity, rate times time, is constant and smooth to the eye.

Time: 20 40 60 80 100
Move: 10 20 30 40 50

Now if there is a delay in the game loop due to processing requirements or a poor resolution timer, the velocity become jittery as well as change speeds, either increasing or decreasing.

Time: 15 50 80 95 130
Move: 10 20 30 40 50

In the above case, the animation not only stutters but arrives late to the destination point. In a perfect timer world, this can be smoothed out by sleeping the game loop for constant amount of time. Mark the time at the very beginning of your game loop. Subtract the amount of time at the end of the game loop. This will give you a negative number. Add a delay that is greater than the negative number and viola you have smooth graphics. The game loop is always performed at the same time.

long sleep = delay+ loopTime-System.currentTimeMillis();

Now if my sleep interval is negative, I start getting the jitters on the display. If I don't put any sort of delay in at all, I can get 500 FPS or more but here come major jitters. Now you will notice if I'm always sleeping for 30 milliseconds for every loop with a positive sleep number calculation, my FPS will be around 33 FPS and never more. 1000/30 = 33.

My dreams of 100 FPS are starting to fade. The only way I can achieve 100 FPS is if my delay is set to 10 milliseconds. 1000/10 = 100. That means for any amount of processing, map rendering, sound, path finding, my PC only has 10 milliseconds to calculate it all. I did a quick test on my home computer and found some bugs in Java. I went to 9 milliseconds and it worked fine with a 1000 sprites. However on my lap top, even with very few slights I was starting to see a jitter of +/- 15 milliseconds. So the minimum delay for my lap top is about 20, depending on what other slow downs my engine introduces.

On a positive note, I did some research and the human eye does pretty well with anything around 18-24 FPS similar the the speeds of video and film. Of course there are a lot of exceptions on how the eye works in the real world like blurring which is not possible on a monitor. One interesting thing that seems pretty important is refresh rate of the monitor versus what is displayed on the screen. The eye actually becomes tired when these two things are different. For example if your screen is refreshing at 72hz or 72FPS the optimum for the game would 72 as well.

Assuming that your game can run smoothly without jitter, the best way to set your frame rate would be dynamically at the screen refresh rate. Another way to approach this, would be to test your worst processing moments (when your game loop is slowed to the absolute maximum amount for that pc) and then set your delay to a value greater than this maximum processing delay by a few milliseconds. It would be very cool to do this dynmanically. Something like set to delay to whichever is worse, process delay or screen refresh rate. At some point I may try to implement this, depending if Java 2D gives me enough wiggle room.

In the mean time, my desktop pc runs fine at 9 millisecond delay, even with a thousand sprites. For fun I tested 10,000 sprites and could still set a delay at 25 before going negative. Note I will discuss the Java/Microsoft bug of 10 milliseconds increments in the next part. However on my laptop 9 milliseconds gives me a negative sleep number. At 20 delays were 4, 4, 4, 4, 3, 4, -5, -5, -5, -6, 3 6 per loop. For even a pretty small amount of blitting I had to set delay to 30 to avoid negatives, pushing my FPS down to 33.

Bollocks! My dream of 100 FPS is gone. But games are vain. How a game looks is extremely important to gamers. My new mistress is smooth, sexy graphics. With that in mind, I'm happy to divorce my original goal of speed at any cost. We do have a new rule though.

Rule: Sleep must be positive for all target machines.

I have a feeling that this is going to be hard to figure out when a game is completely flushed out. I think the maximum delay that I would like to go would be 50 which gives 20 fps. I really prefer though to keep the FPS as high as possible, as close to the refresh rate as possible.

0 comments:

Post a Comment

Thanks for the comment.