Game Loop Falling Behind on Slower Machines

Hi all,

I’m having problems where my game loop falls behind on slower machines and is not able to keep up with the frame rate I have set. I’m working on a metronome application which I will be moving over to mobile devices, so having this program run on slower devices is very important as I want it to work well for anyone who uses it.

This code runs flawlessly as long as the machine is fast enough to keep up. I ran it for close to 20 minutes or so on a fast laptop and the visual stayed in perfect sync with the audio, no problems at all.

I’m using JLabels and sprite sheets for my animations, which as I understand means that I can’t use some of the fixes I’ve found for handling this problem on slower machines. Methods like variable frame rates or changing how far objects move during each update based on how fast the computer moves through the loop seem like they require motion to be based on physics calculations instead of sprite sheets.

I’ve tried a few different methods using a constant frame rate. Initially I tried using the Util Timer, but this was really bad on the slow machine and I had no way of allowing it to skip ahead when it fell behind since it does all the timing stuff itself. Then I tried my own version of checking the system time and checking to see if it has time to spare to sleep or if it needs to rush ahead by skipping over the paint method…this worked a little better, but would cause glitches in the graphic where it would freeze for a bit and then start moving again. Also, even when it was moving smoothly the timing was off from the audio.

The current method I’m using now is one I found in this article:


This also used the technique of skipping the paint method, and so far this method seems to produce the smoothest animations (no long freezing glitches), but this still doesn’t keep time correctly with the audio on slower machines.

The only change I made to the method used in the article is I removed the option to reset the nextTime variable if it falls too far behind. I have two frame counters going, one on the audio side and one on the visual side and it seems like if I were to reset nextTime on the visual side that would cause it to simply drop those frames instead of trying to make them up. Thus the visual frame counter would never catch back up to the audio’s frame counter and the two would be permanently out of sync.

Here’s the entire working example which I posted to pastebin in case anyone wants to run my code and/or tweak it.
http://pastebin.java-gaming.org/7bb7d715d0b13

And here is the animation I made for it:
animation.jpg

Here is just the visual loop part of my code, where I believe the problem is. Thanks! :slight_smile:

	// LOOP
	public Runnable loop = new Runnable(){
		public void run(){
			nextTime = System.currentTimeMillis();
			
			while (isPlaying){
				currentTime = System.currentTimeMillis();
				
				if (currentTime >= nextTime){
					update();
					nextTime += targetLoopDelay;
					
					if ((currentTime < nextTime) || (skippedFrames > maxSkippedFrames)){
						edtPaint();
						skippedFrames = 1;
					}
					else{
						skippedFrames++;
					}
					
					frameCount++;
				}
				else{
					sleepTime = (nextTime - currentTime);
					try {
						Thread.sleep(sleepTime);
					} catch(InterruptedException ie){}
				}			
			}
		}
	};
	
	// UPDATE
	public void update(){
		for (int i=0; i<2; i++){
			updateAnimation(i);
			updateBeatDisplay(i);
		}
	}
	public void updateAnimation(int i){
		if (frameCount >= animationFrame[i]){				
			animationPanel[i].setSubImage(imageIndex[i]);
			
			imageIndex[i] += rightDirection[i] ? 1 : -1;
			if (imageIndex[i] == 0) {
				rightDirection[i] = true;
			}
			if (imageIndex[i] == 8) {
				rightDirection[i] = false;
			}
			
			animationFrame[i] += (long)(frameRate / 8);
			// division rounding fix
			if (frameCount % 25 == 0){
				animationFrame[i]++;
			}
		}
	}
	public void updateBeatDisplay(int i){
		if (frameCount >= beatDisplayFrame[i]){
			currentColor[i] = (int)(labelIndex[i] % 2);
			currentCount[i] = (int)((labelIndex[i] % 4) + 1);
			labelIndex[i]++;
			
			beatDisplayFrame[i] += frameRate;
		}
	}
	
	// PAINT
	public void edtPaint(){
		final int[] finalCount = currentCount;
		final int[] finalColor = currentColor;
		
		SwingUtilities.invokeLater(new Runnable(){
			public void run(){
				for (int i=0; i<2; i++){
					paintAnimation(i);
					paintBeatDisplay(i, finalCount, finalColor);
				}
			}
		});
	}
	public void paintAnimation(int i){
		animationPanel[i].repaint();
	}
	public void paintBeatDisplay(int i, int[] finalCount, int[] finalColor){
		beatDisplay[i].setText(""+finalCount[i]);
		beatDisplay[i].setBackground(colors[finalColor[i]]);
	}

Your biggest first problem is that you are using JPanels and JLabels for animating game objects, which is not at all encouraged. Instead, we recommend you to try to keep a single Canvas, set it’s preferred size and add it to a JFrame. Then create a BufferStrategy and use active rendering. Here’s a small guide for that.

Another thing is that you can’t rely on Swing for your games. If your game is getting big, you will see some performance problems like the one you got now. It is recommended to switch to OpenGL and use some library like LibGDX.

Hi SHC, thank you for your response. :slight_smile:

The method I’m using now was worked out in another thread I had started here…which is rather long. lol

I wasn’t aware that swing was going to be such a problem performance wise, that’s a real bummer! :frowning:

I don’t know that I can use any 3rd party libraries because I’m going to be using Codename One for developing my program on mobile devices, which uses their own Java API that is translated to native code for various mobile devices (Android, iOS, Windows Phone, Blackberry, etc). Everything I’ve been working on in my Java prototype I’ve been checking against the Codename One API to make sure the classes I use are also supported in Codename One.

I searched the Codename One API for “BufferStrategy” and it does not appear that this is supported in Codename One. Here is the Codename One API:
https://codenameone.googlecode.com/svn/trunk/CodenameOne/javadoc/index.html

Essentially what I need in my metronome are setting controls, such as text fields to enter numerical values, buttons (start/stop, tap tempo, etc), sliders (for tempo, volume, etc). Then I will have the visual display which will involve the beat counters (which is also changing color currently) and sprite animations. That’s about it!

It seems I need a mix of swing components and graphics (for animation) and not many tutorials seem to cover how to do all of this, which I think is why I’m getting so stuck on this. I’m usually pretty good at finding information, but this has been difficult finding anything close to what I need. Your article is about the only tutorial I’ve seen that goes into this kind of thing. However, you (and the article you posted) don’t actually recommend using swing at all for games…so that also complicates things.

If I was just sticking with Java then using 3rd party libraries wouldn’t be so much an issue. But I don’t think I’d be able to get them to work with Codename One when I move to mobile unfortunately.

So given all of these things, what seems like the best path forward? I’ve re-written my graphics code several times starting from complete scratch and it seems each time I try something different I still end up running into some kind of road block. I was really hoping this latest one would be more easily fixed with some tweaks to my game loop, but if this is still not the best route to go, then I’d rather do it a better way.

Is there another route I can go implementing a double buffer on my own? I read your article and it sounds like BufferStrategy essentially chooses the best method between double buffering or page flipping…so couldn’t I implement a double buffer myself using other Java components (which would be supported by Codename One) instead of relying on BufferStrategy? This is essentially what I started out trying to do originally in my other thread I posted above, but my method was not successful at all.

Thanks again!

Yes there is another route. Drop Codename One (whose server build code is proprietary whereas the homepage claims “Codename One is open source & free for use!”) and use LibGDX, don’t rely on black boxes. I don’t know why you would go on using a tool that isn’t optimized for games. Codename One seems to be enough for near real-time rendering but not for games. If you stick with Codename One, only use very simple components (in com.codename1.ui) and don’t override the painting. Codename One supports text fields, sliders and buttons of course. The problem is that you need to animate a sprite :s

Hi gouessej, thanks for the reply! :slight_smile:

Yeah, the server builds on Codename One is certainly a drawback. I wasn’t looking forward to that for sure especially if the whole process takes a while to get your code back from their server. ???

I’ve done a little bit of research into LibGDX and I saw that it does a similar thing to Codename One in that it also writes native code for mobile devices. I wasn’t able to find much in the way of direct comparisons to Codename One other than a general mention that LibGDX is geared more towards games and Codename One is geared towards applications…but I’m not sure what specifically that involves. I do know they have very different API’s just from a quick glance at them. I was originally leaning more towards Codename One still because it’s API was closer to Java SE, but now I’m sensing that may not be such a good thing. LOL

One other thing I noticed is that LibGDX doesn’t appear to support Windows Phone where Codename One does. I don’t really know how many people use Windows Phones, but maybe this would be a worthwhile tradeoff if the overall program would end up being a lot better if done in LibGDX?

I will give LibGDX a more solid look now that it is appearing this may be the better route to go in.

Thanks again! :slight_smile:

Windows Phone seems to be stagnating, I’m not sure that the choice of an API should be dictated by its support. Look at LibGDX Scene2D. I can’t advise you to use JogAmp’s Ardor3D Continuation yet as its OpenGL-ES support is partial (ES 1 ok, ES 2 & 3 nok) and there is no plan to support all mobile operating systems except Android and GNU Linux distros (including Raspbian).

Hi gouessej,

I’d like my app to be supported by as many devices as possible, so the number of devices that an API supports is something I’m taking into consideration. However, it seems like I may not get the performance that I want out of standard Java and Codename One, and LibGDX does support everything else that Codename One supports minus Windows Phone…so the tradeoff might be worth it.

Although, I googled LibGDX to Windows Phone and I found a forum post talking about the possibility of going from LibGDX to HTML5 and then using PhoneGap to convert the HTML5 to Windows Phone…that’s certainly taking the scenic route, but maybe something like this would work?

For my metronome I shouldn’t need any kind of 3D animations. I have very basic animation needs really, just a few displays keeping a count of the current beat and 2D animations of an analog-style metronome.

I’ve looked a little harder at the LibGDX API and holy smokes it is totally different! lol It kind of feels like learning a brand new language, I didn’t even see basic java components I need like ArrayLists and such. I believe there are lists in LibGDX, but I just need to learn the new terminology now.

Thanks again!

  1. Ideally, your app would be structured in such a way that how it renders itself is separate and independent from the rest of the code and thus easily portable between frameworks.

  2. For simple animation, even measly Java2D is perfectly capable performance wise.

  3. You can use any part of the standard library whilst using libGDX.

Hi BurntPizza, thanks for the response! :slight_smile:

In regards to point 3 about using the standard library with libGDX…does this include converting to mobile devices? If so, how does the entire Java library get converted to mobile devices? From looking into Codename One you had to stick to their API in order for the code to be translated to the various devices. Is this the same with LibGDX or do they support converting the entire Java library? If they do, then I am totally SOLD on LibGDX!!! :slight_smile:

Thanks again!

http://www.robovm.org/docs

Scroll until you see the blue box.

I’d have a look around the net to see exactly how capable RoboVM is, but it seems pretty good.
(Disclaimer: I haven’t used it before)

http://www.badlogicgames.com/wordpress/?p=3063

3rd line Mario says it works for the whole JRE.

Keep in mind that by “the whole std lib whilst using libGDX” I am assuming you won’t be using AWT/Swing/Java2D as that would mostly defeat the purpose of libGDX. But stuff like java.util (ArrayList) is trivial. (libGDX does have it’s own collections though)

EDIT: Cero you deleted your post! Now it looks like I’m triple posting. Eh whatever.

BurntPizza,

Wow!!! :o I had no idea LibGDX supported the entire Java library otherwise I would have gone this route a lot sooner. Looking at the info you posted, RoboVM is how they convert to iOS? So I assume they have other tools they use to convert the Java library to the other platforms as well since it also supports Android, Blackberry, and HTML5?

I think I’m sold on LibGDX! This sounds amazing. :slight_smile:

Like I said you’ll have to look around and maybe experiment to be sure.
But you can guarantee portability just by staying within libGDX’s APIs, which is the simplest solution.

Thanks BurntPizza!

Do you know if there is another place where they list the standard Java libraries that is guaranteed to be supported by LibGDX? The LibGDX API only includes their libraries and doesn’t include anything from the standard Java API (which is why I didn’t know they actually did support Java standard libraries). I just want to make sure I don’t end up mixing things that can’t be mixed, like for example you said not to use AWT and Swing, so I want to make sure I’m not doing weird things like trying to use basic containers like JFrames to enclose the LibGDX animations if that is not going to work.

Thanks again! :slight_smile:

Assuming a well-designed system (hah), you can usually do things that make sense.
Things that don’t make sense aren’t allowed by the system:

How do you use AWT/Swing inside of libGDX? You would need a (J)Frame as the top-level, in libGDX it’s a LWJGL Display (which in libGDX you never have to actually interact with)

(ok, it is possible, render components to BufferedImage and upload to OGL as a texture, but I digress as that is even less than a total hack)

If you’re used to Swing, but are interested in making the switch to libGDX, the analogous API is Scene2D.ui

BurntPizza,

YES! Scene2D.ui that’s the one! Thank you so much.

I guess that’s what I need is to find some good tutorials on Java --> LibGDX equivalents. Such as, are you looking for a JButton? Use LibGDX Scene2D.ui Widgets Button instead. :wink:

I had no idea LibGDX was so awesome! Thank you SHC, gouessej, and BurntPizza for pointing me in this direction. :slight_smile:

Sorry to contradict you a very little bit. LibGDX has several backends for desktop and mobile environments, one of them uses JGLFW, another one uses Android GL, another one uses GWT, another one uses JogAmp… Only the current (August 17th, 2014) default desktop backend works like you say. It’s just a small reminder. I agree with the rest.

You’re quite right. Of course it’s still abstracted over as ApplicationListener, but you are indeed correct.

gouessej,

So basically, it sounds like LibGDX combines a variety of different existing tools together under “one roof” so to speak and allows them all to be used from a single code base? Is that correct?

Also, one more small question…

Is there a preferred IDE for use with LibGDX? For example, when I asked this question about Codename One on their forum, the developer specifically stated to use NetBeans that they use it and they tended to release more updates for it and it worked better overall with Codename One. Is there a similar preference for LibGDX? I have limited experience with both NetBeans and Eclipse, so I have no real personal preference either way. Which ever one has better LibGDX integration or even has more LibGDX tutorials available…I’ll go with that one. :slight_smile:

Thanks again!