如何加快这个摆动动画?
我正在把一个动画画到一个摇摆的JPanel上。 1024×1024屏幕分为2000个部分,完全覆盖屏幕(不重叠)。
每一块都是一小块屏幕(1/2000’)。 动画通过更改缓冲图像中的像素并调用reaint(),每毫秒绘制一个片段。 所以在整个屏幕上每2秒更换一次。 动画在java.util.Timer任务中运行。
缓冲的图像不会加速且不易变。 我将它的优先级设置为1。
框架根窗格已优化。 前后缓冲都是加速但不易变的。
这很好用。
分析表明,几乎所有的grahics时间都是按照人们的预期绘制缓冲图像,使用一些脏矩形似乎不会有助于缩短绘制时间。
如果我使用它的确切形状剪切缓冲图像的绘图,那么该部分将被绘制并且屏幕的其余部分变为白色。
我想要的是让屏幕的其余部分保持原样并且只是将剪裁的形状涂上颜色。
为每个片段制作像素需要混合10层,因此在那里进行了一些计算。 可以/应该在awt计时器线程中做得更好吗?
或者我应该使用canvas和更新技巧http://java.sun.com/products/jfc/tsc/articles/painting/src/UpdateDemo.java
我见过的建议包括Toolkit.getDefaultToolkit()。setDynamicLayout(true); System.setProperty( “sun.awt.noerasebackground”, “真”);
其他建议包括paintimmedialtely,并inheritanceJComponent而不是JPanel。
我发现这有点令人困惑。
我想尽可能保持这个操作系统独立,但该应用程序将主要在Windows 7上运行。
我接下来的下一个(小)逻辑步骤是什么?
更新:使用canvas(没有更新技巧)显着减少了绘制缓冲图像所花费的时间。 而不是这个在探查器的顶线,我找不到它! 当我使用面板时,我可能会比我应该做的更多。
以下是一些建议:
-
严格检查每毫秒
repaint()
的必要性; 特别是,看看是否可以合并某些更新。 -
考虑
java.swing.Timer
的便利性,它在EDT上呈现并支持合并事件。 -
当不需要缩放时,调用
drawImage()
是最快的,如此AnimationTest
所示。 -
始终尽可能预先计算图像,如此
KineticModel
中所示,该KineticModel
演示了几种动画技术。 -
此处还显示了在
KineticModel
使用的TexturePaint
。 -
这里说明的
IndexColorModel
可能适用。 -
sscce将允许您隔离各种方法以便于分析。
编辑更好的例子
基本上我们可以使用RepaintManager
来跟踪/更新我们每毫秒更改的几个像素。 脏区域将累积,直到油漆实际上能够发生。 当绘制发生时,它使用paintImmediately(int x, int y, int w, int h)
函数(除非整个组件都是脏的) – 所以我们只是更新图像的一小部分。 希望示例代码不依赖于操作系统 – 如果它不适合您,请告诉我。
import java.awt.*; import java.awt.image.BufferedImage; import javax.swing.*; public class UpdatePane extends JPanel{ final int MAX = 1024; //The repaint manager in charge of determining dirty pixels RepaintManager paintManager = RepaintManager.currentManager(this); //Master image BufferedImage img = new BufferedImage(MAX, MAX, BufferedImage.TYPE_INT_RGB); @Override public void paintComponent(Graphics g){ g.drawImage(img, 0, 0, null); } public void paintImmediately(int x, int y, int w, int h){ BufferedImage img2 = img.getSubimage(x, y, w, h); getGraphics().drawImage(img2, x, y, null); } public static void main(String... args) { SwingUtilities.invokeLater(new Runnable(){ @Override public void run() { final UpdatePane outside = new UpdatePane(); outside.setPreferredSize(new Dimension(1024,1024)); JFrame frame = new JFrame(); frame.add(outside); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); outside.new Worker().execute(); } }); } //Goes through updating pixels (like your application would) public class Worker extends SwingWorker{ int currentColor = Color.black.getRGB(); public int x = 0; public int y = 0; @Override protected Integer doInBackground() throws Exception { while(true){ if(x < MAX-1){ x++; } else if(x >= MAX-1 && y < MAX-1){ y++; x = 0; } else{ y = 0; x = 0; } if(currentColor < 256){ currentColor++; } else{ currentColor = 0; } img.setRGB(x, y, currentColor); //Tells which portion needs to be repainted [will call paintImmediately(int x, int y, int w, int h)] paintManager.addDirtyRegion(UpdatePane.this, x, y, 1, 1); Thread.sleep(1); } } } }