orkun
orkun

Reputation: 385

Specific objects flickering when repainted

This question is not "whole screen is flickering" type of question.

I am trying to understand Java graphics and made a simple game, but when the scene is redrawn with new objects, some objects keeps flickering, odly not the whole screen.

Here is my render() method:

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

private void render() {
        BufferStrategy bs = this.getBufferStrategy();
        if(bs == null){
            createBufferStrategy(6);
            return;
        }
        Graphics g = bs.getDrawGraphics();
        Graphics2D g2d = (Graphics2D)g;
        //fill screen with black background
        g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        //draw cool stuff
        try {
            for (int i = 0; i < Element.elements.size(); i++) {
                Element.elements.get(i).render(g2d);
            }
        } catch (Exception e) {
            System.err.println("No such element to render");
        }
        //dispose graphics
        g.dispose();
        g2d.dispose();
        bs.show();
}

What can possibly cause this problem? I dont think amount of bubbles cause this problem.

If you want to check out, this is the project zip file, and this is the .jar file

Upvotes: 0

Views: 214

Answers (1)

teppic
teppic

Reputation: 7286

Your model update, which is being done in the event thread on mouse move, needs to be synchronized with your render thread. The flicker happens because your model is sometimes in an inconsistent state when the render occurs.

One way to fix this is to render in the thread that you're updating your model in. You can run your render in the event thread with SwingUtilities:

try {
    SwingUtilities.invokeAndWait(new Runnable() {
        @Override
        public void run() {
            render();
        }
    });
} catch (InvocationTargetException | InterruptedException e) {
    running = false;
    System.err.println("Render interrupted");
}

If you're using components that are rendered by AWT or Swing you should always do your rendering in the event thread.

As you're controlling the entire rendering process yourself you have the option of rendering in a separate thread, but you will have to synchronize access to your model (that is, writes to the model performed by the event thread should be synchronized with the reads performed by the render thread).

For example:

In Shredder.scan() (called from the event thread)

public static void scan() {
    synchronized (Element.elements) {
        for (Element element : Element.elements) {
            if (element.containsMouse()) {
                if (element.getSize() < 24) {
                    Element.elements.remove(element);
                } else {
                    element.cloneItself();
                    Element.elements.remove(element);
                }
                skip = true;
                break;
            }
        }
    }
}

And in your render thread:

synchronized (Element.elements) {
    for (int i = 0; i < Element.elements.size(); i++) {
        Element.elements.get(i).render(g2d);
    }
}

As a matter of form it would be a good idea to put the code that needs to be synchronized in a single location so that calling code doesn't have to be concerned with maintaining consistency.

Upvotes: 2

Related Questions