【问题标题】:How to get rid of the flicker that appears during my animation?如何摆脱动画期间出现的闪烁?
【发布时间】:2011-08-08 03:14:55
【问题描述】:

我正在通过在 JApplet 中制作一个小游戏来学习 Java。 我的精灵动画有点问题。

代码如下:

this.sprite.setBounds(0,0,20,17);

this.sprite.setIcon(this.rangerDown);
for(int i = 0; i< 16;i++)
{
    this.sprite.setBounds(this.sprite.getX(), this.sprite.getY()+1, 20, 17);
    this.sprite.update(this.sprite.getGraphics());

    try{
        Thread.currentThread().sleep(100);
    }catch(InterruptedException e){
}

}

它在动画过程中留下了一些闪烁。动画结束后,闪烁消失了,但有点难看……我想我错过了一些步骤。 我使用这种方法是因为它现在可以提供更好的结果,但如果可能的话,我希望不使用 AWT,而是使用 Swing。

任何想法如何摆脱闪烁?

感谢阅读。

Screenshoot(无法发布图片,抱歉)。

【问题讨论】:

    标签: java swing flicker


    【解决方案1】:

    这不是影子。它是你的精灵的边界。它恰好是黑色的,并显示为阴影。如果你改变你移动精灵的数量(比如说 50 像素,而不仅仅是 1),你会明白我的意思。

    要解决这个问题,您需要在每次更新精灵位置时绘制背景。虽然这可能会产生闪烁。

    正确的做法是改变绘制对象的方式。您需要覆盖面板的 paintComponent 方法,然后在每次更新精灵的位置时调用 repaint。

    编辑:

    有关基本用法,请参阅此代码示例。注意:这不是您应该使用线程编写动画的方式。我写它是为了向您展示paintComponent 方法中发生了什么,并编写动画线程来向您展示您提到的“阴影”已经消失了。永远不要在线程中有一个非结束的运行循环:)

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    
    
    public class Test {
    
        public static void main(String[] args) {
            JFrame f = new JFrame("Test");
            MyPanel c = new MyPanel();
            f.getContentPane().add(c);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setSize(350, 100);
            f.setVisible(true);
        }
    
    }
    
    class MyPanel extends JPanel {
    
        int x = 0;
        boolean toTheRight = true;
    
        public MyPanel() {
            new Thread(new Runnable() {
    
                @Override
                public void run() {
                    while (true) {
                        x = (toTheRight)?x+5:x-5;
                        if (x>300)
                            toTheRight = false;
                        if (x<0)
                            toTheRight = true;
                        repaint();
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            Graphics2D g2 = (Graphics2D)g.create();
            g2.setPaint(Color.white);
            g2.fillRect(0, 0, getWidth(), getHeight());
            g2.setPaint(Color.red);
            g2.fillOval(x-2, 50, 4, 4);
        }
    
    }
    

    【讨论】:

    • 感谢您的回答。有没有办法用 Swing 做到这一点?对于一件简单的事情,这似乎是一个相当复杂的方法。
    • 这是使用 swing 在面板上绘制自定义事物的默认方式。您覆盖paintComponent,它为您提供了一个Graphics 对象,您可以安全地将其转换为Graphics2D 对象并执行您的操作。此方法还确保您的绘图将被双缓冲,因此您不必担心闪烁。
    • 好吧,“闪烁”这个词让我可以在 Google 上找到信息。我将继续寻找一个简单的解决方案。再次感谢。
    • 您可能还想通过在接受答案的同时点赞答案来表示感谢:P :P :P
    • 我不能:需要 15 个代表。对不起。
    【解决方案2】:

    问题在于双缓冲。

    在小程序中: 双缓冲几乎是自动完成的。在您的方法中调用 repaint() 而不是 paint。

    在 Swing 中,有很多方法可以做到这一点。我通常选择 BufferStrategy 路线。初始化框架时,请执行以下操作:

    JFrame frame;
    ... code to init frame here
    frame.createBufferStrategy(2);
    

    然后在你的绘制方法中:

    Graphics g = getBufferStrategy().getDrawGraphics();
    ..code to do drawing here...
    g.dispose();
    getBufferStrategy().show();
    

    【讨论】:

    • 如果我改变“this.sprite.update(this.sprite.getGraphics());”到“this.sprite.repaint()”,没有动画:只有最后一个位置的精灵可见。我相信 repaint() 方法只有在程序无事可做时才真正使用。但是,我确实在其他地方看到了该解决方案,所以我可能没有正确使用 repaint() 方法。它在 JApplet 中,我从未使用过 JFrame(不是 getContentPane() JFrame 在 JApplets 中的替代品吗?)。好吧,我使用 update() 是因为它给出了最好的结果,但我想尽可能多地使用 Swing。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-03
    • 2013-05-19
    • 1970-01-01
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    相关资源
    最近更新 更多