我想使用java swing制作动画。我有一个for循环,可以稍微更改图像的位置。我的问题是如何使每个循环执行花费指定的时间?
这是我所做的,但是我不知道如何使用wait(),也不知道有没有更好的方法。

// inside of a MyJPanel class extending JPanel
for (int i = 0; i < FJframe.FRAMES; i++){
    long start = System.currentTimeMillis();
    animationFrame = i;
    this.repaint();
    long end = System.currentTimeMillis();
    long remainder = (end - start);
    System.out.println(remainder);
    try {
        this.wait(200 - remainder);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}




编辑

在这里,我重写的Jpanel PaintComponent()
    //一些图纸
    drawChanges(g,getDelta(),animationFrame,FJPanle.FRAMES);

在drawChanges(图形g,ArrayList增量,int框架,int框架)中:

// a switch_case with cases similar to this one.
case AGENT_ATTACK:
// tu phase badi animation e kill
    //drawImage(g2d, map[delta.getCell().x][delta.getCell().y], attacker);
    source = map[delta.getSource().x][delta.getSource().y];
    dest = map[delta.getDestination().x][delta.getDestination().y];
    distanceX =  dest.getCenter().x -
            source.getCenter().x;
    distanceY = dest.getCenter().y -
            source.getCenter().y;
    if (counter < frames / 2){
        g2d.drawImage(ImageHolder.attacker, source.getBounds().x + (int)(((float)counter/frames) * distanceX),
                source.getBounds().y + (int)(((float)counter/frames) * distanceY),
                null);
    }
    else{
        g2d.drawImage(ImageHolder.attacker, dest.getBounds().x - (int)(((float)counter/frames) * distanceX),
                dest.getBounds().y - (int)(((float)counter/frames) * distanceY),
                null);
    }
    break;




我希望每个循环花费例如200毫秒。我该如何实现?

最佳答案

可能不是可接受的答案,但评论太久:

根据实际意图,有几种选择。您描述的模式在“简单游戏循环”中并不少见。在这种情况下,与您发布的代码类似的代码在自己的线程中运行,并定期触发repaint()以便绘制更新的游戏状态。在您的情况下,似乎只增加了animationFrame变量。对于这样一个简单的动作,已经提到的替代方法可能就足够了:


https://stackoverflow.com/a/21860250/中whiskeyspider的建议:您可以将java.util.TimerTimerTask一起使用,而该animationFrame仅更新javax.swing.Timer
或者,您可以使用ActionListener,其animationFrame更新animationFrame。这在这里可能是有利的,因为您可以确保java.util.Timer的更新发生在事件分发线程上。因此,例如,此变量的更新不会干扰其在绘制方法中的使用
但是如注释中所述:执行您已经发布的代码(稍作改动)的自己的线程也是可行的,并且本身并非“错误”-但请注意,在这种情况下(类似于使用animationFrame ),您可能需要自己处理同步




编辑:基于编辑后的问题:类似于我的预期,您在绘画方法中使用animationFrame。这里的关键点是有关如何使用paintComponent变量的详细信息。例如,如果您的animationFrame方法如下所示

class MyJPanel extends JPanel {
    private int animationFrame = 0;

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        drawChanges(g, getDelta(), animationFrame, FJPanle.FRAMES);
        drawSomethingElse(g, animationFrame, ...);
        drawEvenMore(g, animationFrame, ...);
    }

    ...
}


那么可能会在执行java.util.Timer方法时更改paintComponent的值(由另一个线程(可能是drawChanges线程)更改)。这意味着drawSomethingElseanimationFrame可能为javax.swing.Timer接收不同的值。这可能会导致渲染伪影(错放的图像,瓷砖之间的撕裂等)。

可以通过使用animationFrame来避免这种情况(因为paintComponent的更新将在与执行animationFrame的线程相同的线程上完成),或者通过确保所有绘制操作使用相同的值来避免的javax.swing.Timer-大致如下:

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        int animationFrameUsedForAllPainting = animationFrame;
        drawChanges(g, getDelta(), animationFrameUsedForAllPainting , FJPanle.FRAMES);
        drawSomethingElse(g, animationFrameUsedForAllPainting , ...);
        drawEvenMore(g, animationFrameUsedForAllPainting , ...);
    }


但是除此之外,在这种情况下,上述方法之间没有太大的区别。因此,为简单起见,您可以使用java.util.Timer(或在确保有关绘画操作的更新是“线程安全的”时使用)。

关于java - 在指定时间内执行部分代码,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21860153/

10-10 01:19