Archived

This topic is now archived and is closed to further replies.

sponge

[java] System.currentTimeMillis() / regulating game speed

Recommended Posts

Hi, I read somewhere that you should avoid using System.currentTimeMillis() whenever possible. Why is this? And also, what else could you use that is equally simple to regulate you game''s speed? Only a simple way to make sure each frame is not displayed less than a certain amount of time. i.e. More a speed limiter. Thanks..

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You don''t use that method because for most operating systems it''s resolution is only 50ms. This is bad because any frame that takes less than 50ms is treated as taken 50ms, which effectively limits you to 20fps. The solution is to use either a native timer (easy to write yourself), there is also a pure java timer around here somewhere (maybe someone else can post, and help with that), or you can use Java 1.5.0''s System.nanoTime()

Share this post


Link to post
Share on other sites
LWJGL includes a hi-res timer. You can check it out at http://www.lwjgl.org/.



First make it work, then make it fast. --Brian Kernighan

The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)

Do not interrupt your enemy when he is making a mistake. - Napolean Bonaparte

Share this post


Link to post
Share on other sites
Sure, but you can do this to get good game timing
from System.currentTimeMillis():

long step = 0;

// Do this before the FIRST frame only.
long start = System.currentTimeMillis();

// One frame of fabulous Java game programming goes HERE.

// Now, here''s the delay code, after each frame.
// We calculate how long the game SHOULD take to run
// to this point, compare this to how long the game
// HAS been running, and if the latter is less than
// the former, we sleep until things are back in sync.
// This smooths out the timer resolution issue nicely.
// You could have a problem if the game ran for
// many zillions of frames and an integer overflow occurred,
// but if that''s a real concern for you, no big deal -- just
// reset "start" to the current time once an hour or something.

int frameDelay = 1000 / framesPerSecond;
long now = System.currentTimeMillis();
long elapsed = now - start;
long ideal = step * frameDelay;
if (ideal > elapsed) {
try {
Thread.getCurrentThread().sleep(ideal - elapsed);
} catch (Exception e) {
// Yeah, whatever
}
} else {
Thread.yield();
}
step++;




Thomas Boutell
Boutell.Com, Inc.
Purveyors of quality web resources since 1993.

Share this post


Link to post
Share on other sites
boutell: There are 2 problems.

1. As discussed, System.currentTimeMillis() only has a maximum resolution of 50ms. This only allows a maximum framerate of 20fps. For a game to be perceived as smooth, 20 is not bad, but 33 should be the minimum to shoot for.

2. Your method locks the framerate and makes all calculations based on framerate. You should make all calculations based on time and allow the framerate to be as fast as possible. This makes your game run at the same speed on all computers.



First make it work, then make it fast. --Brian Kernighan

The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were. - John Fitzgerald Kennedy(35th US President)

Do not interrupt your enemy when he is making a mistake. - Napolean Bonaparte

Share this post


Link to post
Share on other sites
quote:
Original post by Anonymous Poster
You don't use that method because for most operating systems it's resolution is only 50ms.



Thats only true on win 98/me and it will be at most 50ms although it can vary down to 30ms, very erratic.

MacOSX and linux are really quiet decent and win 2000/xp isn't too bad.

Also you can let the rendering run flat out and only update the game logic every X ms like:


while(true) {
render();
if(System.currentTimeMillis()-lastTime > 30) {
update();
lastTime = System.currentTimeMillis();
}
}


[edited by - nonnus29 on April 7, 2004 7:13:20 PM]

Share this post


Link to post
Share on other sites
quote:
You don''t use that method because for most operating systems it''s resolution is only 50ms. This is bad because any frame that takes less than 50ms is treated as taken 50ms, which effectively limits you to 20fps.


nonnus is correct, windows from nt onwards has, i believe, about a 15ms resolution, and osX and linux are both around 1ms.

also, if you ever get output from currentTimeMillis() youll notice you would *not* get 50ms everyframe in win98. if it has been less than the resolution since your last test, you will get 0 as the time since then, and if it is more, then youll get the full 50ms...in other words, its similar to an integer divide, no "fractional" time between the two, almost always.

what this means, though, is that you can average out the framelengths...and you definitely want to do this if you want to do framerate independent movement because a delatT of 0 is completely useless.

Share this post


Link to post
Share on other sites