有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用线程正确显示精灵

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

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();
}

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

我怎样才能有一个液体显示器? 谢谢

编辑----------------------- 我还有一个问题。 在我的董事会课程中,我把我的爆炸放在一个数组列表中。 但是当爆炸线程结束时,我必须删除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) 个答案

  1. # 1 楼答案

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

    • 在后台线程中进行Swing调用(ActionListener/计时器代码)
    • 对计时器对象重复且不必要地调用start。我不知道你想用这段代码做什么
    • 通过getGraphics()获取图形对象,但它不会获取持久化图形对象

    相反

    • 为精灵动画使用SwingWorker或Swing计时器
    • 在EDT上进行所有Swing调用,除非您从API文档中知道该方法是线程安全的编辑:在前面的回答中已经告诉过您这一点
    • 阅读Swing教程中有关如何进行Swing绘制的内容,包括如何使用BuffereImage以及如何在JComponent或其子组件(如JPanel)的paintComponent方法中绘制

    如果你仍然被困,那么考虑创建和发布一个{A1}来演示你的问题。

  2. # 2 楼答案

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

    您可能需要研究一种称为双缓冲的技术。这涉及到使用两个图像缓冲区在屏幕上渲染图像。它的工作原理是这样的:不是直接将图像绘制到屏幕上,而是将其绘制到内存缓冲区中。仅当渲染完整个帧时,才在屏幕上显示帧。这有助于消除闪烁

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

    在屏幕上显示前在内存中渲染每个帧应有助于消除闪烁

  3. # 3 楼答案

    在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上正确绘制