慢双缓冲法

Slow double buffering method

我一直在尝试在我的游戏库中实现双缓冲,但它比没有它要慢得多。

这是我的 class 实现的。基本上,它绘制到图像上,然后将图像绘制到 JPanel 的图形上 (pg)。

public abstract class DrawingPanel extends GameLoop {

    private BufferedImage image;
    private Graphics2D ig;
    private Graphics pg;

    private int backgroundRGB;

    public DrawingPanel(final int fps, final int ups, final JPanel panel, final Color background) {
        super(fps, ups);
        initialize(panel, background);
    }

    /**
     * Creates a panel with 60 fps and 120 ups
     *
     * @param panel
     * @param background
     */
    public DrawingPanel(final JPanel panel, final Color background) {
        this(60, 120, panel, background);
    }

    public DrawingPanel(final JPanel panel) {
        this(panel, Color.WHITE);
    }

    public DrawingPanel(final int ups, final JPanel panel, final Color background) {
        super(ups);
        initialize(panel, background);
    }

    private void initialize(final JPanel panel, final Color background) {
        image = GraphicsUtils.createImage(panel.getWidth(), panel.getHeight(), Transparency.OPAQUE);
        ig = (Graphics2D) image.getGraphics();
        pg = panel.getGraphics();
        GraphicsUtils.prettyGraphics(ig);
        backgroundRGB = background.getRGB();

        panel.addMouseListener(this);
        panel.addMouseMotionListener(this);
        panel.addKeyListener(this);
        panel.addMouseWheelListener(this);

        panel.setFocusable(true);
        panel.requestFocusInWindow();
    }

    @Override
    public void draw() {
        // set background
        Arrays.fill(((DataBufferInt) image.getRaster().getDataBuffer()).getData(), backgroundRGB);

        // draw on the buffer
        draw(ig);
        // draw our buffer to the screen
        pg.drawImage(image, 0, 0, null);
    }

    public abstract void draw(Graphics2D g);

}

结果: 这意味着 25% - 6% = 19% 的时间花在了 draw 方法上!

我以为可能是因为我用的是Array.fill,结果发现不是没用"premature optimization;"如果我把那行换成

ig.setColor(backgroundColor);
ig.fillRect(0, 0, image.getWidth(), image.getHeight());

花费的时间更长:26 - 5% = 21%。有什么方法可以加快此方法的速度吗?

顺便说一下,GraphicsUtils.createImage 从我的 GraphicsConfiguration 创建了一个兼容的图像。

如果您想查看整个代码,整个库是 on github

这不是 Swing 中绘画的工作方式 -> pg = panel.getGraphics(); 这是一个非常糟糕的主意。您正在 Swing 的被动渲染引擎和您尝试绘制组件的 "snap shot" 之间进行斗争。

Swing 组件在您正确使用它们时会在内部进行双缓冲,但是,您需要使用 API。

首先查看 Performing Custom Painting and Painting in AWT and Swing 以了解有关 Swing 绘画工作原理的更多详细信息

基本上,发生的事情是,您正在使用 getGraphics 的结果来绘制面板,RepaintManager 出现并决定它需要更新您的组件并重新绘制它,这产生一个空白面板,重复得非常快。这就是导致您闪烁的原因。在 Swing 中,您无法控制绘制过程,您只能要求在绘制周期发生时收到通知(例如覆盖 paintComponent)并向绘制系统发出重绘请求,但这取决于油漆系统实际决定油漆周期何时发生。

相反,首先覆盖面板的 paintComponent 方法并在其中执行所有自定义绘画。使用 repaint 请求更新组件。

如果您 "really" 需要一个活动的绘画过程,请查看 BufferStrategy and BufferStrategy and BufferCapabilities,它为您提供了直接控制何时将输出推送到屏幕设备的方法。