Properly (?) Double Buffered Applet is Really Choppy

Hi all. I looked around here for the proper way to double buffer an applet, and I think I’ve got it, but it’s realllly choppy when it runs. (It’s a little 2d jump 'n run game with not much in it yet). If you have any idea why, please tell =) Thanks!


public class Game extends JApplet implements KeyListener, Runnable
{	
	//doublebuffer stuff
	Graphics bufferGraphics;
	Image offscreenImage;
	Dimension dim;
	
	//constants
	int SCREEN_WIDTH = 800;
	int SCREEN_HEIGHT = 600;
	int SPRITE_SIZE = 64;
	Color BGColor = Color.white;
	int PLAYER_SPEED_X = 10;
	int PLAYER_JUMP_SPEED = 20;
	int GRAVITY_ACCEL = 1;
	
	//directional constants
	int LEFT = -1;
	int RIGHT = 1;
	int STOPPED = 0;
	int UP = -1;
	int DOWN = 1;
	
	//images
	Image playerImage;
	
	//movement
	boolean freeFall = true;
	int playerDirX = STOPPED;
	int playerVelY = 0;
	int playerPosX = 0;
	int playerPosY = 0;
	
	//game control variables
	boolean gameIsRunning = false;
	Thread t;
	
	int i = 0;
	
	public void init()
	{
		addKeyListener(this);
		gameIsRunning = true;
		
		//prepare offscreen image for double buffering
		setSize(800,600);
		dim = getSize();
		offscreenImage = createImage(dim.width,dim.height);
		bufferGraphics = offscreenImage.getGraphics();
		
		playerImage = getImage(getDocumentBase(),"images/playerRight.gif");
		
		t = new Thread(this);
		t.start();
	}
	
	public void run()
	{
		while(gameIsRunning)
		{
			try
			{
				t.sleep(33);
			}
			catch (InterruptedException e) {}
			
			playerPosX += playerDirX*PLAYER_SPEED_X;
			playerPosY -= playerVelY;
			
			if(freeFall)
			{
				playerVelY -= GRAVITY_ACCEL;
			}			
			
			//wraparound
			if(playerPosX < 0)
			{
				playerPosX = 0;
			}
			if(playerPosX > SCREEN_WIDTH - SPRITE_SIZE)
			{
				playerPosX = SCREEN_WIDTH - SPRITE_SIZE;
			}
			
			//stop at the floor
			if(playerPosY > SCREEN_HEIGHT - SPRITE_SIZE)
			{
				freeFall = false;
				playerVelY = 0;
				playerPosY = SCREEN_HEIGHT - SPRITE_SIZE;
			}
			
			repaint();
		}
	}
	
	public void keyPressed(KeyEvent e)
	{		
		//move right
		if(e.getKeyCode() == KeyEvent.VK_RIGHT ||
				e.getKeyCode() == KeyEvent.VK_D)
		{
			playerImage = getImage(getDocumentBase(),"images/playerRight.gif");
			playerDirX = RIGHT;
		}
		
		//move left
		if(e.getKeyCode() == KeyEvent.VK_LEFT ||
				e.getKeyCode() == KeyEvent.VK_A)
		{
			playerImage = getImage(getDocumentBase(),"images/playerLeft.gif");
			playerDirX = LEFT;
		}
		
		//jump
		if(e.getKeyCode() == KeyEvent.VK_SPACE ||
				e.getKeyCode() == KeyEvent.VK_W ||
				e.getKeyCode() == KeyEvent.VK_UP)
		{
			//allow jumping if we're standing on a surface
			if(playerPosY == SCREEN_HEIGHT - SPRITE_SIZE ||
					playerPosX == 0 ||
					playerPosX == SCREEN_WIDTH - SPRITE_SIZE)
			{
				if(playerPosX == 0)
				{
					playerDirX = RIGHT;
					playerImage = 
						getImage(getDocumentBase(),"images/playerRight.gif");
				}
				if(playerPosX == SCREEN_WIDTH - SPRITE_SIZE)
				{
					playerDirX = LEFT;
					playerImage = 
						getImage(getDocumentBase(),"images/playerLeft.gif");
				}
				freeFall = true;
				playerVelY = PLAYER_JUMP_SPEED;
			}
		}
	}
	
	public void keyReleased(KeyEvent e)
	{
		//stop moving right
		if(e.getKeyCode() == KeyEvent.VK_RIGHT ||
				e.getKeyCode() == KeyEvent.VK_D)
		{
			if(playerDirX == RIGHT)
			{
				playerDirX = STOPPED;
			}
		}
		
		//stop moving left
		if(e.getKeyCode() == KeyEvent.VK_LEFT ||
				e.getKeyCode() == KeyEvent.VK_A)
		{
			if(playerDirX == LEFT)
			{
				playerDirX = STOPPED;
			}
		}
	}
	
	public void keyTyped(KeyEvent e)
	{
	}
	
	public void paint(Graphics g)
	{
		//clear screen
		bufferGraphics.setColor(Color.white);
		bufferGraphics.fillRect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);
		
		//draw the player
		bufferGraphics.drawImage(playerImage,playerPosX,playerPosY,this);
		
		g.drawImage(offscreenImage,0,0,this);
	}
	
	public void stop()
	{
		t.stop();
	}
	
    public void update(Graphics g)
    {
         paint(g);
    } 
}

That’s the java 1.1 of doing it. (which is good if you want maximum compatibility). If you don’t mind your users needing a more recent version of java then you might well get better performance by using a BufferStrategy which lets you do the double buffering with hardware acceleration.

do a google search for:
java double buffering buffer strategy

the first result you get seems quite a good explanation of how to do double buffering using a buffer strategy