0

I am trying to make a simple game using Java2D for maximum compatibility. It is working great under Java 8 on Mac OS X Yosemite, but it is not as fluid when I try the same code under Windows 7. The canvas flickers when the JFrame is being resized and this is really ugly.

My application uses an AWT Canvas with BufferStrategy and works like this. Another thread calls repaint when something moves in the environment. But for the window resizing handling, my strategy is the following:

public class TestCanvas
{
    private static final Color[] colors = new Color[]{Color.black, Color.darkGray, Color.gray, Color.lightGray, Color.blue.darker().darker(), Color.blue, Color.blue.brighter().brighter(), Color.white};

    public static void main(String[] args)
    {
        JFrame frame = new JFrame("Test Canvas");
        Container contentPane = frame.getContentPane();
        contentPane.setLayout(new BorderLayout());
        Canvas canvas = new Canvas()
        {
            @Override
            public void paint(Graphics g)
            {
                BufferStrategy bufferStrategy = getBufferStrategy();
                g = bufferStrategy.getDrawGraphics();
                paint100Circles(g);
                g.dispose();
                bufferStrategy.show();
            }

            @Override
            public void update(Graphics g)
            {
                paint(g);
            }

            @Override
            public void repaint()
            {
                paint(null);
            }
        };
        contentPane.add(canvas, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(1000, 1000);
        frame.setVisible(true);
        canvas.createBufferStrategy(2);
    }

    public static void paint100Circles(Graphics g)
    {
        Random random = new Random(0);
        for (int i = 0; i < 100; i++)
        {
            int x = Math.abs(random.nextInt()) % 1000;
            int y = Math.abs(random.nextInt()) % 1000 + (Math.abs(random.nextInt() % 1000) / 25);
            int size = 50 + Math.abs(random.nextInt()) % 50;
            g.setColor(colors[Math.abs(random.nextInt()) % colors.length]);
            g.fillOval(x, y, size, size);
        }
    }
}

Maybe I am not using the BufferStrategy in the right way?

Béatrice Cassistat
  • 1,048
  • 12
  • 37

1 Answers1

1

I use createBufferStrategy(3) but 2 should be ok too.

in this answer you are basically encouraged to use paintComponent, not paint(). to quote:

"The problem here is paint does a number of important jobs, calling paintComponent is just one of them."

You might want to try switching to paintComponent. Everything else you're doing looks pretty much ok.

However having said that, in my own code I don't call paint() or paintComponent() at all. Instead, I write to the bufferStrategy whenever I can (render() loop runs as many times as it can)

I think when you use bufferStrategy you write to the buffer outside of paint() and during paint just write the buffer to screen. like it says in this answer, though it gained no points it might still have valid hints.

So I think either use paintComponent and do your painting right there (you can still set a double buffering strategy I think, but draw to your graphics) or write to the buffer outside of paintComponent/paint and let the component draw the buffer when it wants.

Community
  • 1
  • 1
Joeblade
  • 1,735
  • 14
  • 22
  • Thanks! Removing the paint(), update() dans repaint() and adding a new Timer(1000/30, ActionEvent) with the double buffering strategy does not seems to get rid of the flickering while resizing. – Béatrice Cassistat Nov 25 '14 at 23:45
  • Even when using createBufferStrategy(3) or 4. – Béatrice Cassistat Nov 25 '14 at 23:47
  • And the JPanel implementation with paintComponent() instead of Canvas had less flickering, but it was looking like the double buffering strategy was not working at all with objets looking like being rendered directly on the frame. – Béatrice Cassistat Nov 26 '14 at 00:00
  • Maybe I am missing something? – Béatrice Cassistat Nov 26 '14 at 00:00
  • I'm definitely not an expert on this, I am a little bit scared to make any guesses. There are a number of articles on this. I just know from basic game programming to run a render loop inifinitely, which pushes pixels into the buffer at best speed. And the canvas shows them as they come in. I think overriding paint() causes trouble because that's where it would do (simplified) display.setPixels(buffer.getPixels()). panel.paintComponent is as far as I can tell for rendering directly on a surface rather than double buffering. it decides which areas to replace based on what parts need repainting. – Joeblade Nov 26 '14 at 09:59