我有一个关于 Swing Timer 的问题,特别是如何多次调用 actionPerformed
并等待最后一个 actionPerformed
完成后再执行它。我知道其他人以前也问过这个问题,但我发现没有一个解决方案适合我的程序。
这是我所拥有的:
我正在尝试沿从一个位置到另一个位置的路径使用方形对象(矩形)。路径以正方形对象数组的形式给出(路径是使用 A* 发现的,路径中的所有正方形都添加到 ArrayList 中)。 actionPerformed
方法将方 block 从当前的 x、y 位置移动到下一个位置,下一个是我提到的路径中的下一个方 block 。例如:
起点(移动方 block )位于 x 200,y 50 终点(目标方格)位于 x 300,y 150 到达该位置的路径中的方 block 为(在 x、y 位置): (250, 50), (300, 50), (300, 100), (300, 150)
但是移动的方 block 不是一次移动一个方 block ,而是如下所示移动:(走捷径)。
我相信原因是计时器没有等待 actionPerformed
完成,因此在方 block 开始移动之前,监听器已经接收到最后一个方 block (300, 150) 作为目标,然后移动方 block 直接移动到那里..
这是我的一些代码:
MovementListener(保存actionPerformed)
public MovementListener(Canvas canvas){
this.canvas = canvas;
}
public void setSquares(Square moving, Square target){
this.moving = moving;
this.target = target;
}
@Override
public void actionPerformed(ActionEvent e) {
// I tried adding a boolean here, to indicate if the action is finished or not, what I tried was:
// setRunning(true); (set to false below, see at the end of this method)
if (this.moving.getX() < this.target.getX()){
moving.setLocation((int)(moving.getX() + 10), (int)(moving.getY()));
this.canvas.repaint();
}
if (this.moving.getY() < this.target.getY()){
moving.setLocation((int)(moving.getX()), (int)(moving.getY() + 10));
this.canvas.repaint();
}
// setRunning(false);
}
这是保存监听器和计时器的类:
public Canvas(){
// setup ActionListener
listener = new MovementListener(this);
timer = new Timer(100, listener);
}
public void startTimer(Square moving, Square target){
// I tried using the isRunning variable here, so that the next actionPerformed doesn't get called unless listener is ready
if (listener.isReady()){
listener.setSquares(moving, target);
timer.start();
}
}
这是移动 Action 开始的代码(上面定义了 Square moving
)。另外,向后的 for 循环是正确的,路径 ArrayList 是相反的顺序(最后一个方 block 位于位置 0,路径的开头位于列表末尾):
for (int i = controller.getPath().size()-1; i >= 0; i--){
Square target = controller.getPath().get(i);
canvas.startTimer(moving, target);
}
任何帮助将不胜感激!我已经尝试解决这个问题几个小时了.. 谢谢:)
编辑: 好吧,我按照下面描述的 camickr 的方式让它工作:
新的actionPerformed
@Override
public void actionPerformed(ActionEvent e) {
Square current = controller.getPath().get(0);
if (this.moving.getX() < current.getX()){
moving.setLocation((int)(moving.getX() + 10), (int)(moving.getY()));
this.canvas.repaint();
}
if (this.moving.getY() < current.getY()){
moving.setLocation((int)(moving.getX()), (int)(moving.getY() + 10));
this.canvas.repaint();
} else {
controller.getPath().remove(current);
}
if (controller.getPath().isEmpty()){
canvas.getTimer().stop();
}
}
现在可以了!
最佳答案
for (int i = controller.getPath().size()-1; i >= 0; i--){
Square target = controller.getPath().get(i);
canvas.startTimer(moving, target);
}
在上面的代码中,您迭代设置 Square 位置的循环。在计时器有机会触发之前,正方形位置就设置为末尾,因此您只能看到绘制在最后一个位置的正方形。
当您使用计时器时,您不需要使用循环。定时器取代了循环。您只需启动计时器即可。然后,当计时器触发时,您将执行某些操作。
所以,你的逻辑会是这样的:
- 将 Square 对象添加到 ArrayList
- 启动计时器
- 当 ActionListener 被调用时,你 a) 从 ArrayList 中获取第一个 Square b) 将对象移动到 Square c) 从 ArrayList 中删除 Square
- 当 ArrayList 为空时,您将停止计时器。
关于java - 沿着路径移动对象: How to call actionPerformed only after previous actionPerformed has finished?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49411148/