我想使用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.Timer
与TimerTask
一起使用,而该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
线程)更改)。这意味着drawSomethingElse
和animationFrame
可能为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/