Use Slick2D. It should get you started much quicker than fiddling with glBegin()/glEnd() in pure OpenGL. I remember how hard it was to get texture loading and rendering to work in the beginning. The problem with libraries like OpenGL is that you get so ridiculously bad feedback from the code. If you’re not doing something the right way (especially with textures) you’re just going to get a black screen or a triangle without a texture, or something confusing like that. It’s frustrating and time consuming so I really recommend that you start out with Slick2D, if only just for the built in texture loading, e.t.c. Move over to pure LWJGL if you feel that Slick is limiting you in some way, or you just want to take a peek under the hood.
Because doing a busy loop on your CPU overheats your video card. That doesn’t make much sense. I believe that most games use a varying time step. I know that all CoD games do, which in fact resulted in the extremely amusing floating point rounding error bug that makes your character jump higher if you reach a certain FPS, the same problem you see in Ra4king’s climbing game if you disable sleeping. There is a reason why they limited the max FPS in CoD to 90. xD Mostly fast paced games that don’t need determinism use varying time steps.
Most strategy games use a fixed time step though as they need determinism. For example, the game engine used in C&C Generals, LotR The Battle for Middle Earth and C&C 3 (and probably the later C&C games too) is having it’s maximum rendering speed limited by its updating speed, which is usually as low as 25 FPS. Many people complained about the fact that it’s not possible to get a higher FPS for more fluent movement in these games without having to actually increase the game speed (which means that the whole game goes faster). The problem could have been solved by implementing interpolation into the rendering process, which is exactly what the most advanced game loop implementation does in the article I linked before. So really, it’s not like these AAA games are doing any magic here to neither prevent stuttering nor having good game loops. You’ve just never noticed it before.
Also: Rule no. 1 of overheating: It is NEVER EVER a game’s fault that your computer overheats. Either the overheating component in your computer has insufficient cooling, or there is a software bug in the fan controller or something similar, but it can in no way be your game’s fault. Consider this: You’re drive up on a freeway with your new car, and when you reach 70 km/h your car explodes. Is it your fault? Of course not. You were using the car well within it’s specifications. It shouldn’t be possible for you to cause your car to explode in any way in the first place. Such a problem is obviously a hardware problem and not a fault of the one driving the car. Okay, maybe having the car explode is a weird example, but I hope you get the idea.
I’m (pretty) sure that Swing by default is VSynced (including BufferStrategy) on my computer, but I’d love to be proved wrong. That way I can laugh more at how unreliable Java2D is and how good life is on the green OpenGL side of life. xD
I’ve been thinking about putting together a tutorial for detecting, diagnosing and preventing stuttering, both Java specific problems and general problems related to the graphics pipeline. I get the feeling my mile-long posts are being a little bit ignored here, so I’m wondering if anyone would find that useful, or think that someone else (newbies?) would find it helpful/interesting. I’m thinking of splitting it up into three main parts: Detecting stuttering (finding out if your program stutters), diagnosing stuttering (find out what causes it) and finally preventing/fixing it. Thoughts?
A yield does nothing, so then the next frame is rendered asap, there is more than one way to do a busy loop. Hence the rendering frame rate (not the display frame rate) could be very high. Thus it would tax the video cards far more than needed. As a results some poor machine setups and a buggy thermal monitor in some ATi cards meant they overheated and would shut down. The nvidias would just slow down. Even if that wasn’t the case the fan would wind up to max, while other eye candy games this was not happening.
I totally agree that hardware should be able to handle what software can through at them (in this case, not like software defined radio etc). But that does not help your PR after the fact and the game forums where abuzz with negative feedback. Right on top of release that is bad karma no matter how you slice it.
Frame rates being attached to game rate is nothing new. Quake was like that, anything less that 120fps in the later days you couldn’t make some of the map designed rocket jumps. Or even just plain jumps. The frame rate limiting is a bit hacky IMO. I would make the physics independent of the frame rate.
I do this in my current game in that the engine is decoupled from the view. The game rate is about 5-10 turns per sec. While the frame rate can be much higher. Thus the graphics code has less “work” to sync with. TBH i have not had huge problems with stuttering. Well none in fact. But then i have only tested on linux.
PR… I thought this was a game programming forum, not a game marketing forum. xD xD xD My game will have a setting called “Stupid Artificial Slowness”, which when enabled pops up a confirmation screen where you must agree to the terms of use which basically say that I have the right to ridicule you for driving an exploding car. Yeah, that will be awesome.
Concerning your own game, do you not do any interpolation of the game state during rendering? If not, what is the point of redrawing the exact same frame over and over again?
It is fully interpolated. Its also a RTS where latency is less of a issue. At 10 game turns per sec you effectively have a ping on the order of 100ms. Of course i can make that higher. The nice part of the design is that the logic is very independent from the view. Also the separation made network support easier too.
As for stuttering, I have really had no problems so far and i have not being doing anything fancy. In fact i think i still have Thread.sleep loop. Again only on linux. Also i am not taxing my video cards.
Huh? Was that meant to be “is not VSynced”? Otherwise, I’m confused why you’d love to be proved wrong! Having had a quick look at the source for Component, it also seems to try and automatically insert an ExtendedBufferCapabilities when creating a BufferStrategy, in certain circumstances. What exactly those are and when VSync should be enabled is hard to determine - it’s spaghetti in there!
Nope, it’s correct. I think I remember my BufferStrategy not being able to go above 60 FPS, but I might just be mixing things up. Maybe I was forcing VSync with my drivers? xD
I tried, but I still got stuttering, remember? Also, doesn’t Slick2D use Display.sync(60)? Don’t quite know how to use its features without using one of its GameContainers.
[quote]I remember how hard it was to get texture loading and rendering to work in the beginning.
[/quote]
I don’t think I’ll have to worry about this; when I tried LWJGL, I used a texture loading method provided in one of Kevin Glass’s tutorials.
I would find it useful, but seeing as I, being kind of a noob, haven’t quite gotten how to detect, diagnose and prevent stuttering after reading your posts (albeit in a rush), perhaps you could make your tutorial be a more concise and dumbed down version of your posts.
EDIT: Anyone care to demonstrate a smooth fixed timestep loop in either LWJGL or Slick2D?
Alright, I’ll try it some time; but again, I think we were saying that Display.sync(60), which I think Slick2D uses for its gameloop, causes stuttering.
Thank you very much; I guess I’ll give Slick2D another go too, then. Has anyone looked at or tried the Slick2D example I posted, by the way? Here it is again:
@Override
public void update(GameContainer container, int delta)
throws SlickException {
double now = Sys.getTime() * 1000000000.0 / Sys.getTimerResolution();//*/
int updateCount = 0;
//Do as many game updates as we need to, potentially playing catchup.
while(now - lastUpdateTime > timeBetweenUpdates && updateCount < maxUpdatesBeforeRender) {
innerUpdate();
lastUpdateTime += timeBetweenUpdates;
updateCount++;
updatesPerSecondCount++;//
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > timeBetweenUpdates) {
lastUpdateTime = now - timeBetweenUpdates;
}
interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime) / timeBetweenUpdates));
//Update the frames we got.
int thisSecond = (int) (Sys.getTime() / Sys.getTimerResolution());
if (thisSecond > lastSecondTime) {
updatesPerSecond = updatesPerSecondCount;//
updatesPerSecondCount = 0;//
lastSecondTime = thisSecond;
}
deltaDisplay = delta;
}
public void innerUpdate() {
for (int i = 0; i < positions.length; i++) {
positions[i] += directions[i] * (SPEED * i + SPEED);
if (positions[i] <= 0) directions[i] = 1;
else if (positions[i] >= DEFAULT_WIDTH) directions[i] = -1;
}
for (int i = 0; i < positions.length; i++) {
lastPositions[i] = positions[i];
}//*/
}
@Override
public void render(GameContainer container, Graphics g)
throws SlickException {
//double now = Sys.getTime() * 1000000000.0 / Sys.getTimerResolution();//*/
g.scale(DEFAULT_SCALE, DEFAULT_SCALE);
g.setColor(Color.lightGray);
g.fillRect(0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);//*/
g.setColor(Color.red);
for (int i = 0; i < positions.length; i++) {
int x;
if (drawInterpolated) {
x = (int) ((positions[i] - lastPositions[i]) * interpolation + lastPositions[i]);
} else {
x = (int) positions[i];
}
for (int j = 0; j < 2; j++) {
//g.fillRect(x, HEIGHTS[j] + 16 * i, 16, 16);
sprite.draw(x, HEIGHTS[j] + 16 * i);
//fonts[j].draw(":)", x, HEIGHTS[j] + 16 * i - 16);
}
}
g.setColor(Color.white);
g.drawString("Hello, Slick world!", 16, 100);
g.drawString("Delta: " + deltaDisplay, 16, 116);
g.drawString("Updates per second: " + updatesPerSecond, 16, 132);
g.drawString("Sys.getTime(): " + Sys.getTime(), 16, 148);
g.drawString("Sys.getTimerResolution(): " + Sys.getTimerResolution(), 16, 164);
g.drawString("" + Sys.getTime() * 1000000000.0 / Sys.getTimerResolution(), 16, 180);
g.drawString("Interpolation: " + interpolation, 16, 196);
/*interpolation = Math.min(1.0f, (float) ((now - lastRenderTime) / timeBetweenUpdates));
lastRenderTime = now;//*/
/*for (int i = 0; i < positions.length; i++) {
lastPositions[i] = positions[i];
}//*/
}
Saucer, your Slick2D example doesn’t make much sense for the idea of Slick IMHO. Way too complicated.
Slick basically works by calling update() and render() in a loop. The time spent between the previous and the current update call is passed in milliseconds as delta. That’s it. Update your positions by multiplying with a factor and the delta and you’re done.
You can finetune Slick by switching on vsync, setting a target frame rate, delta smoothing, minimal and maximal update time and so on.
But basically I would start simple.
Give the games in my signature a try: they are all done with Slick, the source code to all those games is available on my website or part of MarteEngine. See if they stutter that much that you consider them unplayable or annoying (stuttering wise, not gameplay :P).
SpiderTrap is completely based on calculations using the delta value. Back to the past and StarCleaner use a target frame rate of 60.
Don’t overcomplify things - try to get some games done ;D
Thank you for your advice, Tommy, but I’m specifically trying to avoid using that style of updating. Do you know the distinction between fixed and variable timesteps, or about making the physics framerate independent? I’m trying to implement fixed timesteps (independent physics), and that’s (sorta?) what’s causing the stuttering.
EDIT: I guess I could try to fix the delta on Slick’s terms— as, after further consideration, I think you may be suggesting— by using various features such as minimal and maximal update time, but I feel that that would be too indirect; in other words, although the raw code seems more complicated, in the end it sounds to me like trying to incorporate a fixed timestep directly would be a lot simpler than trying to force Slick’s internals to make a fixed timestep out of a variable timestep.
EDIT EDIT: Ah, this looks sort of promising:
[quote]http://slick.cokeandcode.com/wiki/doku.php?id=controlling_game_updates
[/quote]
Somehow I get the impression that setting both the min and the max to what I want (and thus achieving fixed timesteps?) will be a little less robust than directly doing it myself, but that remains to be seen. Also, I wonder if those functions only take integers…? An update rate of 60 updates per second corresponds to an interval of not exactly 16, nor exactly 17, right… I guess I’ll still have to try similar things with LWJGL, but without Slick.
Saucer, I even wrote a tutorial (!) about a gameloop using fixed timesteps for updates and required tweening for rendering.
Unfortunately it’s for BlitzMax but of course the principle works the same regardless of the programming language (and BlitzMax has most OO features you’d require).
The code can easily be converted to Java and Slick. I would suggest you create your own AppGameContainer subclass where you implement your own game loop using the mechanisms above.
I guess this would be the cleanest way to introduce a different update/render behavior into Slick.
Ah, my apologies. Thank you for the tutorial! If I remember correctly I’ve seen this tutorial before, but I didn’t look too closely at it because it was for BlitzMax. If I find an opportunity, I’ll see if I’ll be able to convert it to Java successfully, and report back with results!
So currently I know of at least 10 different versions of the fixed timestep loop— all from various sources, some of those sources being examples of code that people have submitted here— so I prepared three different versions of the LWJGL example Cero posted, each of which incorporates one of the different fixed timestep code examples.
I’ve bundled together those examples in a single download, along with some other example programs (like a similar Game Maker example) and the source for all the different examples. You can download it here: box.com download
Note: example_simple.jar and example_variabletimestep.jar are examples without fixed timesteps; they’re there for comparison.
There are various settings you can toggle within the JARs, like vsync and the usage of Thread.yield and Thread.sleep. More details are contained in the included readme file.
Here’s what I discovered:
-With certain settings, the stuttering can be improved pretty well on all tested computers (at least one school computer, our desktop, and my laptop).
-Rendering as fast as possible seems to yield fairly smooth graphics, but it seems that our desktop and my laptop have difficulty with that kind of rendering (I can’t tell if it’s difficult for the computers at my school).
-I finally saw that LWJGL’s vsync actually does have an effect, and yields some of the smoothest rendering I’ve seen yet! (That is, with Java.) …However, although this smooth rendering was achieved on a computer at school, it doesn’t seem to work on our desktop or my laptop. In fact the API documentation for LWJGL says:
[quote][About Display.setVSyncEnabled:] This call is a best-attempt at changing the vertical refresh synchronization of the monitor, and is not guaranteed to be successful.
[/quote]
That being said, I think at least one particular setting on one example may yield suitably smooth rendering all around: example_delventhal.zip without Display.sync, with yield and sleep, and without frequent yield and sleep. It still stutters with those settings, but, if I’m not mistaken, it only stutters a little more than does the Game Maker example.
Admittedly, I don’t know how this setting fares on a computer on which vsync works; it may have to be turned off on such computers. But then again, on such a computer, vsync might yield smooth rendering on its own.
EDIT: I guess it’s also possible that the smooth rendering that seemed to be achieved with vsync on the computers at my school could only have been achieved with the speed of those computers (they seem pretty fast).
Just another thing worth mentioning: not all monitors run at 60Hz - some will be 72hz or 75hz etc. This will screw your timing unless you change the display mode to 60Hz.
Ooh, good point. I think I do know of a way to get the default refresh rate, though; I wonder if that will be enough to accommodate this issue. Also, I found something you posted at lwjgl.org in 2010, Cas; it’s contained in the following forum thread:
EDIT: That’s strange, for some reason I can’t get the link to work… The title of the thread is “Timer Comparison.”
Would it be alright if I made a new example (as in, add another new member to my examples download) based (heavily) on your method?