Skip to main content
GameDev.net gamedev.net
🔒 Locked

[java] Java applet performance

Started by Abob Dec 22, 2002 at 9:27 PM 5 replies 1.1k views
Original Post
Abob
Abob
I am a C++ programmer who recently started to learn java because I want to write applet games. I am using java 1.1 so people wont have to download java 2 to run it. The problem I am having is that I just can’t get the speed I need. I know good games can be written in java 1.1 because I see them on the Internet. Below is a simple applet that bounces 10 rects around with double buffering. I think it is the double buffering that is killing it. Even running that in 500 x 300 it just goes slow on my computer(I planned to do the game at 800 x 600) Could people look over the code and see if I am doing something wrong? Or maybe I should just give up java and make the game in c++. Thanks for any help
  
import java.awt.*;
import java.applet.*;
import java.awt.image.*;

public class BounceRects extends Applet implements Runnable {  
	
	Thread MainThread;
	Graphics BackBuffer;
	Image    BackBufferImg;


	final int SCR_X = 500;
	final int SCR_Y = 300;

	final int PAUSE_PER_FRAME = 50;
	
	final int RECT_NUM = 10;
	private boolean drawRects = false;
	
	CRect rects[];
	
	public void init() {
		
		rects = new CRect[RECT_NUM];
		for (int i = 0; i < RECT_NUM; i++) {
		rects[i] = new CRect();	
		}
		
		BackBufferImg = createImage(SCR_X, SCR_Y);
		BackBuffer = BackBufferImg.getGraphics();
	}

	
	public void start() {
		if(MainThread==null) {
     		MainThread = new Thread(this);
    		MainThread.start();
    	} 
    }
	
	
	public void stop() {
		MainThread=null;
	}
	
	public void run() {
		drawRects = true;
		Thread currentThread = Thread.currentThread();
		while(MainThread == currentThread) {
			repaint();
		    for (int i = 0; i < RECT_NUM; i++ ) {
		    	rects[i].update();
		    	}	
		
			
			try {
        		MainThread.sleep(PAUSE_PER_FRAME);
        	}
           	catch(InterruptedException e) {}	
		
		
		}	
	}
	
	public void update(Graphics g) {
		paint(BackBuffer);
		g.drawImage(BackBufferImg, 0, 0, this);	
	}	
	
	public void paint(Graphics g) {
	
		g.setColor(Color.black);
		g.fillRect(0, 0, SCR_X, SCR_Y);
		if (drawRects) {
			for (int i = 0; i < RECT_NUM; i++) {
				
			rects[i].draw(g);	
				}	
		
		}
		
	
		
	}

	class CRect {
	
		public int x, y, w, h, vx, vy;

		CRect() {
			w = (int) (Math.random() * 40) + 5;
			h = (int) (Math.random() * 40) + 4;
			x = (int) Math.random() * (SCR_X - w);
			y = (int) Math.random() * (SCR_Y - h);
			vx = (int) (Math.random() * 10) - 5;
			vy = (int) (Math.random() * 10) - 5;
		}

		public void update() {
			x += vx;
			y += vy;
			if ((x < 0) ||  ((x + w) > SCR_X)) {
				vx = -vx;	
			}	
			if ((y < 0) ||  ((y + h) > SCR_Y)) {
				vy = -vy;	
			}	

		}

		public void draw(Graphics g) {
			g.setColor(Color.red);
			g.drawRect(x, y, w, h);	
		} 

	} // end class CRect





} // end class BounceRects


  
Arrg!!
nonnus29
nonnus29
One problem I see is the ordering of you update() repaint() paint(); The OS calls update when the applet need to be updated, so its called intermittantly. Update calls paint and repaint calls paint. You draw your buffer in update(); it should be drawn in paint so its called every iteration of the loop (in update its not). Also since you are going for only 20 fps timing won''t be an issue on win9x but if you try to go higher it will be.

You can get pretty good frame rates with AWT in applets. The problem is the VAST differences in performance on different OS/browsers combinations. In my 2d sidescrolling ludum dare entry people get anywhere from 0 to 50 fps. It is VERY frustrating.

Check my 2d sidescroller demo at:

www.geocities.com/nonnus29/unionjack/test.htm

And here is a 3d software rendering applet and api at:

www.jpct.net
Cedric
Cedric
APs can''t use HTML tags on these forums.
CaptainJester
CaptainJester
Here is your code, modified to increase performance:

    
import java.awt.*;
import java.applet.*;
import java.awt.image.*;

public class BounceRects extends Applet implements Runnable {
Thread MainThread;
Graphics BackBuffer,gr;
Image BackBufferImg;
final int SCR_X = 500;
final int SCR_Y = 300;
final int PAUSE_PER_FRAME = 50;
final int RECT_NUM = 10;
private boolean drawRects = false;
boolean running=true;

CRect rects[];
public void init() {
rects = new CRect[RECT_NUM];
for (int i = 0; i < RECT_NUM; i++) {
rects[i] = new CRect();
}
BackBufferImg = createImage(SCR_X, SCR_Y);
BackBuffer = BackBufferImg.getGraphics();
}

public void start() {
running=true;
if(MainThread==null) {
MainThread = new Thread(this);
MainThread.start();
}
}

public void stop() {
MainThread=null;
running=false;
}

public void run() {
drawRects = true;
Thread currentThread = Thread.currentThread();
while(running) {
//repaint();

if(gr==null) {
gr=getGraphics();
}
else {
paintMe(BackBuffer);
gr.drawImage(BackBufferImg, 0, 0, this);
}
for (int i = 0; i < RECT_NUM; i++ ) {
rects[i].update();
}
//try {

// MainThread.sleep(PAUSE_PER_FRAME);

//}

//catch(InterruptedException e) {}

}
}

//public void update(Graphics g) {

//paint(BackBuffer);

//g.drawImage(BackBufferImg, 0, 0, this);

//}


public final void paintMe(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, SCR_X, SCR_Y);
if (drawRects) {
for (int i = 0; i < RECT_NUM; i++) {
rects[i].draw(g);
}
}
}

class CRect {
public int x, y, w, h, vx, vy;
CRect() {
w = (int) (Math.random() * 40) + 5;
h = (int) (Math.random() * 40) + 4;
x = (int) Math.random() * (SCR_X - w);
y = (int) Math.random() * (SCR_Y - h);
vx = (int) (Math.random() * 10) - 5;
vy = (int) (Math.random() * 10) - 5;
}

public void update() {
x += vx;
y += vy;
if ((x < 0) || ((x + w) > SCR_X)) {
vx = -vx;
}
if ((y < 0) || ((y + h) > SCR_Y)) {
vy = -vy;
}
}

public void draw(Graphics g) {
g.setColor(Color.red);
g.drawRect(x, y, w, h);
}
} // end class CRect

} // end class BounceRects



If you are looking for performance, you have to throw some standard programming practices out the window.

First, do not rely on the repaint/update/paint methods for your painting. They are called from the event dispaching thread and provide no guaruntees to when the actual calls will be performed. You can get a graphics context anywhere in your code, so get it in the Thread.run() method and do all your drawing there.

Second, do not put the thread to sleep. This is also unreliable for speed. Instead, check to see how much time has passed since the last update and do your calculations accordingly.

Third, make as many methods 'final' as possible. Making methods final causes static binding, which is performed at compile time. Otherwise all methods use dynamic binding which happens at runtime. This will reduce program overhead to produce more speed. This is especially important for methods that are called a lot.(I changed paint to paintMe and made it final)

Fourth, once you are ready to use the program, compile all your classes with the '-g:none' option. This removes debugging information which increases speed.(As a bonus, this also reduces file size)





First make it work,
then make it fast.

--Brian Kernighan

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book

[edited by - CaptainJester on December 24, 2002 10:45:18 AM]
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
nonnus29
nonnus29
Agreed with Capt J except checking time in win9x/ME with System.currentTimeMillis() is less accurate than sleep.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.