Incredible game slowdown [Java Application]

Hey guys, I’m new here but I’m not totally new to java (albeit I am new to java games).
I’ve got a P4 3.4Ghz / 1GB RAM computer which I have been using to develop a project for school. The only problem is, the school computers are much slower (450Mhz & 320MB RAM worst case scenario). My game paints very, very slowly on the school computers but at the desired 60FPS at home. It used to work well in school too but then I added a bunch of stuff and I find it hard to target what exactly is causing the delay. If anyone could help me with this issue, i’d appreciate it much.

Here I have excerpts from Game.java, Game extends JPanel and implements both MouseListener and MouseMotionListener


	/* Paint Method */
   	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2;
		
		// Create bufferImage & set vars if it/they don't exist
		if (bufferImage == null) {
			bufferImage = createImage(this.getWidth(),this.getHeight());			
			g2 = (Graphics2D)bufferImage.getGraphics();
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
			setCursor(cMouse);
		}
		
		// paint on top of the image
		g2 = (Graphics2D)bufferImage.getGraphics();
		g2.setFont(cookies);
		g2.setColor(Color.white);
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.drawImage(background,0,0,null);
		
		AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float).2);
		g2.setComposite(ac);
		g2.setColor(Color.WHITE);
		g2.fillRect(boardOffsetX+2,boardOffsetY+2,316,252);
		ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float)1);
		g2.setComposite(ac);
		
		// draw each block on the board
		for (int y=0; y<8; y++) {
                    for (int x=0; x<10; x++) {
    			Block temp = blocksMap[y][x];
    			temp.drawBlock();
                    }
                }
		
		// draw the cursor	
		if (somethingSelected==1 && selBlock != null && selBlock.blockType != -1 && selBlock.alpha>0) {
			g2.drawImage(bCursor[(int)(counter)%12],boardOffsetX+selBlock.gridX*32+selBlock.offsetX,boardOffsetY+selBlock.gridY*32+selBlock.offsetY,null);
		} else if((somethingSelected==0 || mouseDown==0) && blockInFocus!=null) {
			g2.drawImage(bCursor[(int)(counter)%12],boardOffsetX+blockInFocus.gridX*32+blockInFocus.offsetX,boardOffsetY+blockInFocus.gridY*32+blockInFocus.offsetY,null);
		}

		// draw to the screen
		g2.setColor(Color.black);
		ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float).5);
                g2.setComposite(ac);
                g2.fillRoundRect(5,256+84-2,this.getWidth()-10, 58, 15,15);
                g2.fillRoundRect(5, 5, boardOffsetX-11, 256+84-2-11,15,15);
                g2.fillRoundRect(boardOffsetX, 5,320,boardOffsetY-11,15,15);
                ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER,(float)1);
                g2.setComposite(ac);
		if (mouseHoverButton == 0) {
                    g2.drawImage(navImage[6],this.getWidth()-64-48*3,256+84+3,null);
                } else {
                    g2.drawImage(navImage[0],this.getWidth()-64-48*3,256+84+3,null);
                }
		if (mouseHoverButton == 1) {
                    g2.drawImage(navImage[7],this.getWidth()-64-48*2,256+84+3,null);
		} else {
                    g2.drawImage(navImage[1],this.getWidth()-64-48*2, 256+84+3,null);
		}
		if (mouseHoverButton == 2) {
                    g2.drawImage(navImage[8],this.getWidth()-48-64, 256+84+3,null);
                } else {
                    g2.drawImage(navImage[2],this.getWidth()-48-64, 256+84+3,null);
                }
		if (mouseHoverButton == 3) {
                    g2.drawImage(navImage[9],this.getWidth()-64,256+84+3,null);
                } else {
                    g2.drawImage(navImage[3],this.getWidth()-64,256+84+3,null);
                }
		if (mouseHoverButton == 5) {
                    g2.drawImage(navImage[11],16, 256+84+3,null);
                }  else {
                    g2.drawImage(navImage[5],16,256+84+3,null);
                }
                if (mouseHoverButton == 4) {
                    g2.drawImage(navImage[10],16+48, 256+84+1,null);
                }  else {
                    g2.drawImage(navImage[4],16+48,256+84+1,null);
                }
                g2.setColor(Color.WHITE);
                g2.drawString("Level: " + currentLevel+"",(int)((boardOffsetX-fm.stringWidth("Level: " + currentLevel))/2.0),37);
                g2.drawString("Moves: " + moves+"",(int)((boardOffsetX-fm.stringWidth("Moves: " + moves))/2.0),64);
                g2.drawString("\"Some Kind of String Goes Here\"", (320-fm.stringWidth("\"Some Kind of String Goes Here\""))/2+boardOffsetX,44);
		g.drawImage(bufferImage,0,0,this);
                
    } // end of paintComponent (paint method)

And then I also have two nested threads, one repaints, one does calculations…

	//AnimUpdate repaints the screen at a set interval (~60 FPS)
	class AnimUpdate extends Thread {
		
		//the method run when .start() is called
		public void run() {
			while(Thread.currentThread() == update) {
				//paint & update the frame number
				//repaint();
				System.out.println("from" + System.)
				paintImmediately(0,0,480,400);
				++counter;
				try { //sleep try-catch
					Thread.sleep((int)((1.0/60.0)*1000));	
				} catch(InterruptedException e) {
					break;
				} //end of try-catch block (sleep)
			} //end of while loop
		} //end of run() method
	} //end of class AnimUpdate

and

	class PlayGame extends Thread {
		public void run() {
			while(Thread.currentThread() == pg) {
				
				if (isRunning==0) {
				isRunning=1;
				 //calculations code...very very long....goes here.
				}
				isRunning=0;
				
				
				try {
					Thread.sleep((int)((1.0/60.0)*1000));	
				} catch(InterruptedException e) {
					break;
				}
			}
		}

I also can’t think of a way to sync the two threads, if that is even necessary. I’m almost positive there’s a big flaw somewhere that I don’t see (or in the program’s flow/design or something).
Once again, thanks!

Thats because you aren’t using the right tools.

If you arent using Netbeans yet, download it,. Then download and install the Netbeans Profiler. Finally, profile your app.

Thats how professionals find out why their code is slow. You might as well learn profiling skills now as they will be some of the most valuable you will have.

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);

I’m sure you tested this candidate?

Hmm, alpha composite stuff is also quite demanding. I’d guess one of those two is responsible. It seems most of your rendering is done by means of images. In this case you should consider the INTERPOLATION_BILINEAR renderinghint instead of ANTIALIASING. But try without any of them first.

thanks guys, I have a copy of netbeans but I never tried it’s profiler. I had tried the antialiasing but it didnt seem to kill anything horribly.
I’ll keep you updated; appreciate it.

[edit] I installed the profiler but when I use it, it gives me tons of nullpointerexceptions =(
Is there any flaw in having it set up so that:

Game.java (JPanel) has mouseListeners and mousemotionlisteners
“” “” loads and starts PlayGame thread
game.java loads and starts AnimUpdate thread
AnimUpdate calls paintImmediately() and has a Thread.sleep(16) in a try catch,
PlayGame does calculations and has a Thread.sleep(16) in a try catch

?

don’t you get a conflict between swing painting, you painting, swings dubbelbuffer, your own dubbelbuffer etc.

try seperating the stuff.

Coincidentally, I was playing with that today, wondering about it.
I removed super.paintComponent(g) from the draw method, and when I load the panel, i turn the JPanel’s native doublebuffering setting off.
Slight improvements but there’s still something really killing it, and I haven’t been able to find it out yet.

& on a side note, the profiler didnt work that well…I must have done something wrong, it kept giving me NullPointerExceptions

Yup sounds liek you dont have it installed right.

If youare doing swing then you want to do all your paiting ONLY on the AWT paint thread. Dont knwo if thats relevent or not, just commenting based on the other comment.

search for “swing” + “thread safety” for the details though I doubt its what causing the slowdown.

what “programming-template” do you guys tend to use for games?
Like a while loop for the entire game that calls methods w/a wait at the end, or something multithreaded, etc…
what seems to work best?

I might just try redesigning the format.

Action games are all “near real-time” programs which means they look like this:


WHILE PLAYING {
   Read Input
   Calculate new state
   RenderFrame
}