Sign in to follow this  

Double Buffering Problem

This topic is 2596 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone,

I'm having a lot of trouble figuring out how to apply Double Buffering to this program I'm working on. I've tried several things, but none have worked so far. I've deleted my attempts to make the code more readable. Any help would be greatly appreciated!

My Main class:

import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.awt.event.KeyListener;
import javax.imageio.*;
import javax.swing.*;

public class Map extends JFrame{

private BufferedImage overworld;
private GameCharacter character;
private Vector illegalPoints;

Image offscreenImage;
Graphics offscr;

public Map(){
super("Zelda");
this.setSize(500,350);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

try{
overworld = ImageIO.read(new File("overworld.gif"));
}
catch(IOException e){
System.err.println("Unable to read the map");
}

this.setVisible(true);

illegalPoints = new Vector();
//Add the top, and bottom
for (int i = 0; i < 16; i++ ){
if (i != 7){
illegalPoints.add(new Point(i,0));
}
illegalPoints.add(new Point(i,8));
}
//add the middle points
illegalPoints.add(new Point(14,7));
illegalPoints.add(new Point(11,7));
illegalPoints.add(new Point(10,7));
illegalPoints.add(new Point(9,7));
illegalPoints.add(new Point(8,7));
illegalPoints.add(new Point(9,6));
illegalPoints.add(new Point(10,6));
illegalPoints.add(new Point(1,7));
illegalPoints.add(new Point(1,1));
illegalPoints.add(new Point(14,1));
illegalPoints.add(new Point(8,1));
illegalPoints.add(new Point(9,1));
illegalPoints.add(new Point(10,1));
illegalPoints.add(new Point(11,1));
illegalPoints.add(new Point(9,2));
illegalPoints.add(new Point(10,2));
illegalPoints.add(new Point(4,3));
illegalPoints.add(new Point(4,5));
illegalPoints.add(new Point(12,5));
illegalPoints.add(new Point(12,3));
illegalPoints.add(new Point(0,7));
illegalPoints.add(new Point(0,6));
illegalPoints.add(new Point(0,1));
illegalPoints.add(new Point(0,2));

offscreenImage = createImage(this.size().width, this.size().height);
offscr = offscreenImage.getGraphics();

myKeyListener listen = new myKeyListener();
this.addKeyListener(listen);
}

public boolean isLegalMove(int x, int y){
if (x < 0 || x > 14 || y < 0 || y > 14 ){
return false;
}
else if (illegalPoints.contains(new Point(x,y))){
return false;
}
return true;
}

public void setCharacter(GameCharacter c){
character = c;
this.repaint();
}

public void paint(Graphics g){
//super.paint(g);

g.drawImage(overworld,0,0,null);
if (character != null){
character.draw((Graphics2D) g);
}
}

class myKeyListener implements KeyListener{

public void keyPressed(KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.VK_DOWN: GameCharacter.isDown = true; break;
case KeyEvent.VK_UP: GameCharacter.isUp = true; break;
case KeyEvent.VK_LEFT: GameCharacter.isLeft = true; break;
case KeyEvent.VK_RIGHT: GameCharacter.isRight = true; break;
}
GameCharacter.update();
}

public void keyReleased(KeyEvent event) {
switch(event.getKeyCode()) {
case KeyEvent.VK_DOWN: GameCharacter.isDown = false; break;
case KeyEvent.VK_UP: GameCharacter.isUp = false; break;
case KeyEvent.VK_LEFT: GameCharacter.isLeft = false; break;
case KeyEvent.VK_RIGHT: GameCharacter.isRight = false; break;
}
GameCharacter.update();
}

public void keyTyped(KeyEvent event) {
// TODO Auto-generated method stub

}
}

public static void main(String[] args){
Map m = new Map();
GameCharacter c = new GameCharacter(m);
m.setCharacter(c);
}
}



My Character Class:


import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.*;


public class GameCharacter {

public static BufferedImage up;
private BufferedImage down;
private BufferedImage left;
private BufferedImage right;
public static int moveDirection;
private static int x;
private static int y;
public static int iconSize;

private static Map map;

public static final int UP = 0;
public static final int DOWN = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;

public static boolean isUp;
public static boolean isDown;
public static boolean isLeft;
public static boolean isRight;

public static int drawX = 0;
public static int drawY = 0;

static int vX = 0;
static int vY = 0;

public GameCharacter(Map m){
try{
up = ImageIO.read(new File("Link_back.gif"));
down = ImageIO.read(new File("Link_front.gif"));
left = ImageIO.read(new File("Link_left.gif"));
right = ImageIO.read(new File("Link_right.gif"));
}
catch(Exception e){
System.err.println("Unable to read the file");
}

moveDirection = DOWN;
iconSize = 32;
map = m;
x = 0;
y = 3;
}

public void afterMove(){
map.repaint();
try{
Thread.sleep(20);
}
catch(InterruptedException e){
System.err.println("Woke up early");
}
}

public static boolean checkMapForMove(int x, int y){
if (map.isLegalMove(x, y)){
return true;
}
else{
System.err.println("Illegal Move at " + x + " " + y);
return false;
}
}

public static void update() {
vX = 0;
vY = 0;
if (isUp) {
if(checkMapForMove(x, y-1)){
vY -= 1;
}
moveDirection = UP;
}
if (isDown) {
if(checkMapForMove(x, y+1)){
vY += 1;
}
moveDirection = DOWN;
}
if (isLeft) {
if(checkMapForMove(x-1, y)){
vX -= 1;
}
moveDirection = LEFT;
}
if (isRight) {
if(checkMapForMove(x+1, y)){
vX += 1;
}
moveDirection = RIGHT;
}
}

public void draw(Graphics2D g){
x += vX;
y += vY;
drawX = x * iconSize;
drawY = y * iconSize+iconSize;
if(moveDirection == UP){
g.drawImage(up,drawX,drawY,null);
}
else if (moveDirection == DOWN){
g.drawImage(down,drawX,drawY,null);
}
else if (moveDirection == LEFT){
g.drawImage(left,drawX,drawY,null);
}
else if (moveDirection == RIGHT){
g.drawImage(right,drawX,drawY,null);
}
afterMove();
}
}



Thanks again.

Share this post


Link to post
Share on other sites
hi,

A couple of points to take notice of:

1. You are overriding the paint() method. This is not the correct behavior to do painting in Swing. When you paint yourself you need to override the paintComponent method. that is the proper way in Java.

2. If you have no use for background painting, set the control to be opaque (provides drawing on all its area). This will prevent flickering due to the clearing of the area using the background color. The order of calls is:

paintBackground
paintComponent

So if the control is not opaque, the first one will always create flicker.

3. You don't need to manage the double buffering as it is by nature a part of some java controls. A better approach would be to create a JPanel which is double buffered by default (using BufferStrategy) and will handle everything for you, so draw into IT instead of the JFrame.

In short - use JPanel inside the JFrame and do all your drawing into the JPanel, which is double buffered (so no need for the offscreen members)

4. If you must provide consistent drawing rate like in a game loop, consider using setIgnoreRepaint on your JPanel to prevent the OS from sending paint updates to it. Then, you can update the panel in a loop, per time interval, even from another thread. Effectively creating a rendering loop.


Another nice thing is that you can quite easily enable hardware direct draw blitting when you work with BufferedImage. I don't recall the flags at the moment but it shouldn't be hard to find. If you need help with it let me know.
Also, its quite possible its on by default :-)

Share this post


Link to post
Share on other sites
Thanks, VogueMaster! The BufferStrategy worked perfectly! However, I'm not sure on how to move everything around to create a render loop. You said that I'm overriding the paint method? I'm not sure how to fix this, anymore help would be greatly, greatly appreciated!

Share this post


Link to post
Share on other sites
Quote:
Original post by DranoMax
You said that I'm overriding the paint method?


Yes. I don't understand how you can not be aware of this, but I will try to begin the explanation at the beginning: to "override" a method is to provide an implementation in a derived class (in your case, your Map class) for a method that already exists (i.e. is not declared 'abstract') in the base class (JFrame).

You are not supposed to override the paint() method of JFrame. JFrame::paint() does some unspecified things that you aren't supposed to have to care about, except that one of those things is to call paintComponent() on the current object. Thus, you should override paintComponent() instead (since in the base class it does nothing).

Quote:
I'm not sure how to fix this


You were told exactly what to do: override paintComponent() instead.

Share this post


Link to post
Share on other sites

This topic is 2596 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this