【问题标题】:Execute a part of code in specified time在指定时间内执行一部分代码
【发布时间】:2014-02-18 16:47:56
【问题描述】:

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

【问题讨论】:

  • 使用等待会暂停你的线程。在循环中使用 Timer 可能会更好。
  • 如果您的remainder 大于200,您将获得IllegalArgumentException
  • 虽然还有其他替代方案(如 Timer)可能更适合某些应用案例,以及一些应该修复的细节(如上面提到的 gla3dr),但这并没有错代码一般。你的问题是什么?编辑:好吧,也许使用Thread#sleep(...) 而不是this#wait(...)
  • @gla3dr:是的,没错,但我不知道有什么更好的方法。也许你可以指导我。
  • @Marco13:我正在编写一个简单游戏的图形部分,我想用动画来展示单位运动。所以我需要每隔(例如)十分之一秒重新绘制一次更改。

标签: java swing


【解决方案1】:

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

【讨论】:

【解决方案2】:

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

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

  • 正如whiskyspider 在https://stackoverflow.com/a/21860250/ 中所建议的那样:您可以使用java.util.Timer 和仅更新animationFrameTimerTask
  • 或者,您可以使用javax.swing.Timer,其ActionListener 更新animationFrame。这可能在这里是有利的,因为您可以确定animationFrame 的更新发生在事件调度线程上。因此,这个变量的更新不会干扰它在绘画方法中的使用,例如
  • 但正如 cmets 中所述:执行您已经发布的代码的自己的线程(带有较小的修改)也是可行的,并且本身没有“错误” - 但请注意,在这种情况下(类似于使用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.Timer 线程)同时 paintComponent 方法被执行。这意味着drawChangesdrawSomethingElse 可能会收到animationFrame不同 值。这可能会导致渲染伪影(错位的图像、瓷砖之间的撕裂等)。

这可以通过使用javax.swing.Timer 来避免(因为这样,animationFrame 的更新将在与执行paintComponent 的线程相同的线程上完成),或者通过确保 all 绘画操作使用相同的 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 , ...);
    }

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

【讨论】:

  • 感谢您的回答。关于我的代码,animationFrame 并不是唯一改变的地方。基于这个变量,在 JPanel PaintComponent() 中调用的函数中有很多位置(大约 100 个)发生变化。
  • 好的,那么同步方面就变得更重要了。您必须确保此变量的更改不会干扰您在 paintComponent 方法中所做的事情。除了增加animationFrame 之外,也许您可​​以编辑您的问题以描述您在那里所做的事情,并可能显示您如何使用 animationFrame 变量的简短(!)草图。
  • @alireza 也用 EDIT 更新了我的答案。
猜你喜欢
  • 2014-04-20
  • 1970-01-01
  • 2012-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-20
相关资源
最近更新 更多