重绘时特定对象闪烁

Specific objects flickering when repainted

本题不是“整个屏幕都在闪烁”类型的题。

我正在尝试理解Java图形并制作了一个简单的游戏,但是当用新对象重绘场景时,一些对象一直在闪烁,奇怪 不是整个屏幕.

这是我的 render() 方法:

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();
}

什么可能导致这个问题?我不认为气泡的数量会导致这个问题。

如果您想签出,这是项目 zip file,并且 这是 .jar file

您的模型更新是在鼠标移动时在事件线程中完成的,需要与您的渲染线程同步。发生闪烁是因为在渲染发生时您的模型有时处于不一致状态。

解决此问题的一种方法是在您更新模型的线程中进行渲染。您可以 运行 在事件线程中使用 SwingUtilities:

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

如果您正在使用由 AWT 或 Swing 呈现的组件,您应该始终在事件线程中进行呈现。

由于您自己控制整个渲染过程,因此您可以选择在单独的线程中进行渲染,但您必须同步对模型的访问(也就是说,写入事件线程执行的模型应该与渲染线程执行的读取同步)。

例如:

Shredder.scan()中(从事件线程调用)

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;
            }
        }
    }
}

并且在您的渲染线程中:

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

就形式而言,将需要同步的代码放在一个位置是个好主意,这样调用代码就不必关心保持一致性。