慢双缓冲法
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,它为您提供了直接控制何时将输出推送到屏幕设备的方法。
我一直在尝试在我的游戏库中实现双缓冲,但它比没有它要慢得多。
这是我的 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);
}
结果:
我以为可能是因为我用的是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,它为您提供了直接控制何时将输出推送到屏幕设备的方法。