A smooth game-loop. I think I did it! Why is it working?

Well, a really basic one, at least. The balls are moving smoothly now, and at a firm 60fps instead of the 63-64fps I had been getting for a long time. It only jerks a tiny bit whenever I click away from it, or my anti-virus occasionally scans a file or something. For me, at least :slight_smile:
I’m doing this for an applet-game, but it can be easily converted to work in a windowed game.

I’ve tried out several game-loops posted in this forum, and they all seemed to get me some sort of constant jerkiness, odd FPS or they were timestep-loops (separating logic-updates from renders) which I’m not currently interested in. I suppose this could pretty easily be changed into a timestep-loop, though.

This is a result of several days of pondering over posts on this forum, and scouring the Internet for posts on game-loops, so in essence, you were all part of this, and I thank you all so VERY much! :slight_smile:

Please test it out, and give me your thoughts!

Applet-class: http://pastebin.java-gaming.org/54a6b7d141c
Ball-class: http://pastebin.java-gaming.org/54a6b3d141c

EDIT:
The code I ended up with is in the next post

Own thoughts (and questions):
A - I have no idea if the timerAccuracyThread will help in this case, being executed in init(). An Applet automatically runs init() when started, and I can’t have a Main in an Applet, as far as I know. So where to put it? It doesn’t seem to make a perceptible difference. I left it in anyway.

B - Doing Thread-sleep(0) instead of Thread-sleep(1) also seems to iron out a few kinks. This would be because instead of actually waiting any amount of time (1000000ns = 1ms), I just go back through the while-loop ā€œinstantlyā€, resulting in higher precision of when to get out of the while-loop, but also higher CPU-load, right? Well, setting it to Thread.sleep(1) yields 58-59fps and jerkiness.

C - Using Thread.yield() seems to give me the same performance that Thread.sleep(0) does. I haven’t tested it with tools. I’d like to know which is better. I know yield() supposedly hogs the CPU, but wouldn’t Thread.sleep(0) hog it just as much?

D - What do you guys use to test performance of Java Applets and their CPU-usage?

E - Toolkit.getDefaultToolkit().sync() doesn’t seem to make a perceptible difference, like it did in my full-screen game (which is running very smoothly).

F - When I export it to a JAR and run it in Firefox through an HTML-document, it seems to run as it should (the movement looks like it’s calculated smoothly) but the entire Applet has a spot of constant lag, which isn’t there at all when running it from my IDE, AND the sleepTime is +1ms compared to the IDE. Is that just too bad? I’m on Windows 7, dual-core laptop, newest Firefox, newest Java 6 and 7 installed, using Java 6 for building.
ANSWER: My laptop sucks :slight_smile: My desktop computer is running it perfectly.

Side-note:
I’m getting pretty tired of game-loops, and it seems everyone is having trouble with them. In most posts, people throw their code into the air, many other people nitpick at it, then all of a sudden the OP says ā€œYay, I fixed it using what X and Y said. THANKS!ā€ and buggers off, not bothering to write up the code that solved it all for him. That’s getting really tedious. Please post the loop you end up with, so newbies (like me) can see what happened. That would get us much less posts about this subject.

Here’s a version of it with a sort of delta-timer implemented. The ball-movements are now using doubles for calculations, and only cast their double positions to int in their draw methods, which now get the deltaTime as a parameter for their calculations. As you can see, the balls now move at very different, but stable, velocities, and are all rendered with smooth movement. I might introduce Math-round() in the draw-calculations of the Ball to make them even more precise, but that’s for another day when I make an object that isn’t just a testing-ball.

This seems to be exactly what I need for my side-scroller :slight_smile: I know that timing precise physics might require me to separate the physics from the render-loop, but having 60 updates per second is more than enough for me at the moment.

Applet-class: http://pastebin.java-gaming.org/54a6b8d141c
Ball-class: http://pastebin.java-gaming.org/54a6b9d141c

EDIT:
This is the code I’ve ended up using after applying the fixes discussed in this thread. Ball-class is the same as above.
Applet-class: http://pastebin.java-gaming.org/54a6b4d241c

The whole Thread.yield() in a while loop was great for a while until we noticed that it consumes A TON of CPU time. I figured out an equally smooth ā€˜sleep’ that uses very little CPU:


long sleepTime = //figure out sleepTime

long now = System.nanoTime(), diff;
while((diff = System.nanoTime()-now) < sleepTime) {
    if(diff < sleepTime*0.8)
        try { Thread.sleep(1); } catch(Exception exc) {}
    else
        Thread.yield();
}

Thanks for your answer.

How do you see that, young master ra4king? Could you share how you test how much CPU time is being used on a particular application, in this case an Applet?

Well, the difference between my original loop and when I put in your snippet there instead, is that my sleep-time has dropped about 1½ millisecond, which seems to indicate it is doing a lot more thinking. Is this the tradeoff you’ve been talking about? A little more calculations, a lot less hogging?
It still seems equally smooth, though.

I was just looking at the task manager, and with the simple yield loop, the Java process was almost always 100%. With my loop, it was at barely 5-10%.

Wow, that’s very cool ;D

If I put sleep(0) into your loop instead, I get about 1ms back on my sleepTime-per-loop, but CPU load seems to rise to twice the amount. That’s crazy!

My results for the record:
Thread.sleep(sleepTime) - constant switching between 7% and 15% processing power used; introduces lag
Thread.sleep(1) while-loop - 7-14% processing power used; introduces lag
Thread.yield() while-loop - 25-28% processing power used constantly; no lag
ra4king’s hybrid - 13% processing power used constantly; no lag

Well, it seems what you’ve done is figure out a method that gets rid of the jerkiness of using just Thread.sleep(1) and the horrible CPU hogging when using Thread.yield(). You are indeed the king!

Now that you’re here, do you have an answer for question A?

Glad to help! You might want to start using BufferStrategy for painting, here’s a good link for that and other stuff. Good luck! :slight_smile:

Thanks, I got that part down, though. Just tried to keep it simple for the test-app :slight_smile:

Do you know if the timerAccuracyThread-method works in applets and if I’ve put it in the right spot?

Yup, you’re good :slight_smile:

You’re an egyptian angelman. THANKS!

Oh damn I didn’t see any of the edits!

We’ve already gone through A-D

E: I believe BufferStrategy takes care of that for you, but it really doesn’t do much.
F: You’re way too picky. With more action on the screen, no one will notice anything. :stuck_out_tongue:

Hehehe, I’m only glad to help! ;D

Well, now I’ve removed the manual image-flipping, and followed this example of implementing a BufferStrategy. It is working quite well, and I’ve gained 2ms on my sleepTime :smiley:

Thanks again for your help, ra4king! I know I’m picky, but I just want to LEARN!

Posting my end code if anyone finds this thread looking for solutions:

Happy delta applet-code: http://pastebin.java-gaming.org/54a6b4d241c
Delta-ball can be found in second post from the top.

EDIT: Corrected the code to incorporate ra4king’s suggestions in the post below.

One thing, though…why does he have bufferStrategy.show() before his entire draw-block, and you have yours in the double do-while loop (which I stole)?

Because mine is the way the BufferStrategy Javadoc recommends it to be :slight_smile:

Also, you don’t need that call to update(g) in there at all. Do your own clearing using g.clearRect(0,0,width,height);

Dude, you are just impeckable, aren’t you?! :smiley:

Done! Have some medals!

Hahaha as always I’m just glad to help! :slight_smile:

He’s totally against WOP, and one of the few that actually follows 100% of the JavaDoc :smiley: