Muteking
Muteking

Reputation: 1513

triple buffer heavy flickering

Shouldn't triple buffering and Canvas be an optimal solution for passive rendering? I've just wrote this java code that displays a circle. If I leave bufferstrategy to 3, it flickers so much. If I turn it down to 2 or 1 it's ok. Maybe I'm doing something wrong?

public void run(){

    while (running){   
        update();
        draw();
    }
 }


 public void update(){

 }


 public void draw(){
       BufferStrategy bs = getBufferStrategy();
       if (bs==null){
       createBufferStrategy(3);
       return;
       }

       Graphics g = bs.getDrawGraphics();
       g.setColor(Color.BLACK);
       g.fillOval(30, 30, 20, 20);
       g.dispose();
       bs.show();
 }

and this is the JFrame class where I put the Canvas

public class Game {

public static void main (String [] args){

    Pan game = new Pan();
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setResizable(true);
    frame.add(game);
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    game.start();

}

}

Upvotes: 1

Views: 3545

Answers (2)

MadProgrammer
MadProgrammer

Reputation: 347194

Two things jump out at me.

  1. You "loop" is running without any kind of delay. This means that the screen will be updated as many times as it possible can, this may be to much for the hardware to keep up with. Generally speaking, you want to aim for around 25fps, this help provide the illusion of smooth movement
  2. You are not preparing the Graphics for painting. Each time you get a Graphics context from the BufferStrategy you are actually getting the last that was used. This means, everything that was painted to is still. There you need to clean this up. The flickering is (possibly) coming from the fact that one of the Graphics contexts has already being filled with a color, while the others have not.

The following is a very basic example, including a little bit of animation

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import javax.swing.JFrame;

public class DoubleBuffer {

    public static void main(String[] args) {

        Pan game = new Pan();
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setResizable(true);
        frame.add(game);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        game.start();

    }

    public static class Pan extends Canvas implements Runnable {

        private int xDelta = 2;
        private int x = 0;
        private int y = 20;

        public Pan() {
        }

        public void start() {
            new Thread(this).start();
        }

        public void run() {

            while (true) {
                update();
                try {
                    Thread.sleep(40);
                } catch (InterruptedException ex) {
                }
                draw();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        public void update() {
            x += xDelta;
            if (x + 20 > getWidth()) {
                x = getWidth() - 20;
                xDelta *= -1;
            } else if (x < 0) {
                x = 0;
                xDelta *= -1;
            }
        }

        public void draw() {
            BufferStrategy bs = getBufferStrategy();
            if (bs == null) {
                createBufferStrategy(3);
                return;
            }

            Graphics g = bs.getDrawGraphics();
            g.setColor(Color.RED);
            g.fillRect(0, 0, getWidth(), getHeight());
            g.setColor(Color.BLACK);
            g.fillOval(x, y, 20, 20);
            g.dispose();
            bs.show();
        }
    }
}

Upvotes: 3

H3XXX
H3XXX

Reputation: 647

Try this:

Make a BufferedImage in your myPanel class like this:

private BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);

Now draw that image ABOVE everything else in your draw method like this:

public void draw(){
   BufferStrategy bs = getBufferStrategy();
   if (bs== null){
       createBufferStrategy(3);
       return;
   }

   Graphics g = bs.getDrawGraphics();
   g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
   // Draw your other stuff after this...
   g.fillOval(20, 20, 20, 20);
   g.dispose();
   bs.show();
}

This will draw a black background onto the screen so that it does not flicker anymore. Now you can draw anything on top of that image.

Upvotes: 1

Related Questions