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: