用螺纹正确显示精灵

时间:2012-02-06 18:51:18

标签: java swing animation timer sprite

我正在使用线程来显示带有精灵的动画。

Explosion e2 = new Explosion(this, x2, y2, explosion);    
new Thread(e2).start();

在爆炸课上我有:

public void run()
{
    ActionListener taskPerformer = new ActionListener() {
          public void actionPerformed(ActionEvent evt) {
              cursor++;
          }
    };

    Timer timer = new Timer(50, taskPerformer);

    while(cursor < (sprite.getNbSprite()-1))
    {           
        timer.start();

        drawExplosion();    
    }
    timer.stop();

    compteur--;

}

public void drawExplosion()
{       
    Graphics g = board.getGraphics();
    board.repaint();
    Graphics2D g2d = (Graphics2D)g;
    g2d.drawImage(sprite.getSprite(cursor), x, y, this);
g.dispose();
}

但是在显示过程中我遇到了问题,在精灵的每个图像之间都有一个空白。 就像显示器闪烁一样。

我怎样才能展示液体? 感谢

编辑----------------------- 我还有一个问题。 在我的Board类中,我把我的爆炸放在了ArrayList中。 但是当爆炸线程结束时我要删除ArrayList中的对象。 我有一个ArrayList来存储我的所有爆炸线程吗?当一个线程结束时我删除了爆炸ArrayList中的对象。 公共类委员会延伸JPanel {

Mouse mouse;
ArrayList<Explosion> explosions;
Sprite explosion;

public Board() 
{           
    mouse = new Mouse(this);

    explosion = new Sprite(320,320,5,5,"files/explosion2.png");

    explosions = new ArrayList();

    setDoubleBuffered(true); 

    this.addMouseListener(mouse);
}

public void addExplosion(int x, int y)
{


    for(int i=0; i<100; i++)
    {
        int x2 = (int)(Math.random() * 450);
        int y2 = (int)(Math.random() * 450);

        Explosion e2 = new Explosion(this, x2, y2, explosion);


        explosions.add(e2);

        new Thread(e2).start();

    }

}

public void removeExplosion(Explosion e)
{
    explosions.remove(e);

}


public void paint(Graphics g) {
    super.paint(g);

    Graphics2D g2d = (Graphics2D)g;

    for(int i=0; i<explosions.size(); i++)
    {
        g2d.drawImage(explosion.getSprite(explosions.get(i).getCursorI()), explosions.get(i).getX(), explosions.get(i).getY(), this);
    }

    g.dispose();
}

}

3 个答案:

答案 0 :(得分:2)

你似乎做了很多错事,包括

  • 在后台线程中进行Swing调用(您的ActionListener / Timer代码)
  • 反复且不必要地在Timer对象上调用start。我不知道你要用这​​些代码做什么。
  • 通过getGraphics()获取图形对象,但没有获得持久的Graphics对象。

相反,

  • 使用SwingWorker或Swing Timer进行精灵动画
  • 在EDT上进行所有Swing调用,除非你从API文档中知道该方法是线程安全的 - 编辑:你已经在之前的答案中告诉过你了。
  • 在Swing教程中阅读有关如何进行Swing绘图的内容,包括如何使用BufferedImage以及如何在JComponent或其子像素(如JPanel)的paintComponent方法中绘制。

如果您仍然遇到困难,请考虑创建并发布展示您问题的sscce

答案 1 :(得分:1)

在Swing中,你必须在EDT中完成与Swing相关的所有事情。

// This actually calls paint() in the Swing EDT  
board.repaint(); 
// This runs on your main thread 
// (Never paint anything outside of the EDT!)
g2d.drawImage(sprite.getSprite(cursor), x, y, this); 

你看到一些眨眼,因为board在两个不同的线程中完成了一些绘画并绘制了两个不同的东西。

您需要做的是创建class BoardWithSprite extend JPanel 它会覆盖其paintComponent(g)方法,以便绘制精灵。

然后你可以打电话给boardWithSprite.repaint(),它会在Swing EDT上正确地进行绘画。

答案 2 :(得分:1)

Timer.start()方法用于启动计时器,只应调用一次。它导致ActionListener对象以Timer构造函数中指定的间隔调用。在您的情况下,它将每50毫秒递增一次cursor变量。

您可能希望研究一种名为双缓冲的技术。这涉及使用两个图像缓冲区来渲染屏幕上的图像。它的工作原理如下:不是将图像直接绘制到屏幕上,而是将其绘制到内存缓冲区中。只有在完成渲染整个框架时,才会在屏幕上显示框架。这有助于消除闪烁。

对于第二帧,您执行相同的操作,只有您绘制到第二个缓冲区,因为当前正在使用第一个缓冲区在屏幕上显示图像。完成绘制第二帧后,然后将第二个缓冲区发送到屏幕并使用 first 缓冲区渲染下一帧,依此类推。

在屏幕上显示每个帧之前渲染每个帧应该有助于消除闪烁。