在指定时间内执行部分代码

时间:2014-02-18 16:47:57

标签: java swing

我想用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(Graphics g,ArrayList deltas,int frame,int frames)中:

// 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毫秒。我怎样才能做到这一点?

2 个答案:

答案 0 :(得分:2)

考虑使用Timer。例如,scheduleAtFixedRate()方法。

答案 1 :(得分:1)

可能不是一个可接受的答案,但评论的时间太长了:

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

  • 正如https://stackoverflow.com/a/21860250/中的whiskeyspider所建议的那样:您可以使用仅java.util.Timer的{​​{1}}来更新TimerTask
  • 或者,您可以使用其animationFrame更新javax.swing.Timer的{​​{1}}。这个可能在这里是有利的,因为您可以确定ActionListener的更新发生在事件派发线程上。因此,此变量的更新不会干扰绘制方法中的用法,例如
  • 但正如评论中所提到的:执行你已发布的代码(带有次要适应性)的自己的线程也是可行的,而不是“错误的”本身 - 但请注意,在这种情况下(类似于使用时) animationFrame)您可能需要自己处理同步

编辑:根据编辑过的问题:与我的预期相似,您在绘画方法中使用animationFrame。这里的关键点是有关如何使用java.util.Timer变量的详细信息。例如,如果您的animationFrame方法看起来像这样

animationFrame

然后可能会发生paintComponent的值被更改(由另一个线程,可能是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, ...); } ... } 线程),而执行animationFrame方法。这意味着java.util.TimerpaintComponent可能会收到drawChanges不同的值。这可能导致渲染伪像(错位的图像,在瓷砖之间撕裂等)。

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

paintComponent

但除此之外,在这种情况下,上述方法之间并没有太大的区别。因此,为简单起见,您可以使用animationFrame(或 @Override protected void paintComponent(Graphics g) { super.paintComponent(g); int animationFrameUsedForAllPainting = animationFrame; drawChanges(g, getDelta(), animationFrameUsedForAllPainting , FJPanle.FRAMES); drawSomethingElse(g, animationFrameUsedForAllPainting , ...); drawEvenMore(g, animationFrameUsedForAllPainting , ...); } 来确保更新对于绘制操作是“线程安全的”。)