我对 AnimationTimer 类有问题,我用它来移动圆(球)。 当我运行程序(是乒乓球游戏)时,球停止了一会儿(0.5-1秒),然后继续运动(球运动如此滞后)
这是主控制器类
package com.anas.pong;
import javafx.animation.AnimationTimer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import java.net.URL;
import java.util.ResourceBundle;
public class MainController implements Initializable {
private enum MoveTo {
bottomLeft,
topLeft,
topRight,
bottomRight
}
private MoveTo where;
private Circle ball;
int ballX, ballY;
@FXML
private AnchorPane mainPane;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
// setting the ball
ball = new Circle();
ball.setRadius(13);
ball.setStroke(Color.BLACK);
ball.setFill(Color.BLACK);
// setting position of the ball
ball.setLayoutX(400);
ballX = 400;
ball.setLayoutY(300);
ballY = 300;
mainPane.getChildren().add(ball);
where = MoveTo.bottomLeft;
AnimationTimer movement = new AnimationTimer() {
@Override
public void handle(long l) {
// moving to ...
if (where.equals(MoveTo.bottomLeft))
bottomLeftMovement();
else if (where.equals(MoveTo.topLeft))
topLeftMovement();
else if (where.equals(MoveTo.topRight))
topRightMovement();
else if (where.equals(MoveTo.bottomRight))
bottomRightMovement();
else {
System.out.println("Nothing");
stop();
}
}
};
movement.start();
}
private void bottomLeftMovement() {
// go bottom
ball.setTranslateY(ball.getTranslateY()+2);
ballY += 2;
// go left
ball.setTranslateX(ball.getTranslateX()-2);
ballX -= 2;
if (ballY >= 600-13)
where = MoveTo.topLeft;
else if (ballX <= 13) // 0+13
where = MoveTo.bottomRight;
}
private void topLeftMovement() {
ball.setTranslateY(ball.getTranslateY()-2);
ballY -= 2;
ball.setTranslateX(ball.getTranslateX()-2);
ballX -= 2;
if (ballX <= 13) // 0+13
where = MoveTo.topRight;
else if (ballY <= 13) // 0+13
where = MoveTo.bottomLeft;
}
private void topRightMovement() {
ball.setTranslateY(ball.getTranslateY()-2);
ballY -= 2;
ball.setTranslateX(ball.getTranslateX()+2);
ballX += 2;
if (ballX >= 800-13)
where = MoveTo.topLeft;
else if (ballY <= 13)
where = MoveTo.bottomRight;
}
private void bottomRightMovement() {
ball.setTranslateY(ball.getTranslateY()+2);
ballY += 2;
ball.setTranslateX(ball.getTranslateX()+2);
ballX += 2;
if (ballY >= 600-13)
where = MoveTo.topRight;
else if (ballX >= 800-13)
where = MoveTo.bottomLeft;
}
}
球应该停留在(800,600)的窗口中并且可以工作,但有时球会停止(0.5-1秒),我认为问题来自AnimationTimer类,但我尝试过TranslateTransition和Thread(with while(true))他们都有同样的问题(运动滞后)。
OP 代码使一切变得比必要的复杂得多。 设置为在其
PauseTransition
中自行播放的 onFinished Property
将处理循环动画。
使用
Node.layoutX
和 Node.layoutY
也可能比使用 Node.translateX
和 Node.translateY
更干净,尽管当 Node
留在 [0,0] 然后翻译时不会有太大区别。
如果方向枚举也有要应用的 x 和 y 增量的字段,它会更有用,但实际上完全没有必要。 球将始终具有 X 和 Y 增量(在本例中均为 +- 2.0),并且当到达墙壁时它们会简单地反转。 无论 X 和 Y 增量的当前值是多少,墙壁碰撞的逻辑都是相同的。
当布局基本上不存在时,FXML 或
AnchorPane
就没用了。 因此,一个简单的 Pane
就可以正常工作,并且 Circle
只是添加到代码中,就像在 OP 中一样。
这是 Kotlin 中的版本(所有 JavaFX 想法在 Kotlin 中都是相同的):
class Pong : Application() {
override fun start(stage: Stage) {
stage.scene = Scene(createContent(), 800.0, 600.0)
stage.show()
}
private fun createContent() = Pane().apply {
val ballX: DoubleProperty = SimpleDoubleProperty(400.0)
val ballY: DoubleProperty = SimpleDoubleProperty(300.0)
var moveX = -2.0
var moveY = -2.0
val ball = Circle(13.0).apply {
layoutXProperty().bind(ballX)
layoutYProperty().bind(ballY)
}
children += ball
val animation = PauseTransition(Duration.millis(10.0)).apply {
setOnFinished {
ballX.value += moveX
ballY.value += moveY
if ((ballX.doubleValue() > (800 - 13) || (ballX.doubleValue() < 13))) {
moveX *= (-1)
}
if ((ballY.doubleValue() > (600 - 13) || (ballY.doubleValue() < 13))) {
moveY *= (-1)
}
playFromStart()
}
}
animation.play()
}
}
fun main() = Application.launch(Pong::class.java)
它会运行,球会在
Pane
周围愉快地弹跳,没有任何犹豫或抖动。