我正在尝试使用JavaFX和动画,特别是PathTransition
。我创造了一个简单的程序,让球能够反弹,#34;不使用QuadCurveTo
类。到目前为止,这是我的代码:
Ellipse ball = new Ellipse(375, 250, 10, 10);
root.getChildren().add(ball);
Path path = new Path();
path.getElements().add(new MoveTo(375, 500));
int posX = 375;
int posY = 500;
int changeX = 10;
int changeY = 50;
int gravity = 10; // approximate in m/s^2
int sec = 0;
for(; posY<=500; sec++, posX-=changeX, posY-=changeY, changeY-=gravity)
path.getElements().add(new LineTo(posX, posY));
// How do I equally space these elements?
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(sec*1000));
pathTransition.setNode(ball);
pathTransition.setAutoReverse(true);
pathTransition.setCycleCount(Timeline.INDEFINITE);
pathTransition.setInterpolator(Interpolator.LINEAR);
pathTransition.setPath(path);
pathTransition.play();
我有for
循环穿过二次序列,球以正确的运动(弯曲的路径)移动。
但是,我希望它在曲线顶部(顶点)移动得更慢,因为它移动的距离越小(changeY
,垂直增量变量,随着循环的继续而减小)来模拟更逼真的曲线。但是,它在整个时间内以线性速度行进。
是否有任何方法可以使每个元素在整个时间内保持相等的距离,从而使这个&#34;反弹&#34;会显示正确吗?感谢。
答案 0 :(得分:2)
我根本不会使用时间轴或转换。使用AnimationTimer并根据自上一帧起经过的时间计算新坐标。 AnimationTimer
有一个handle
方法,每个渲染帧调用一次,取一个表示时间戳的值,以纳秒为单位。
SSCCE(弹性添加到物理学中):
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class BouncingBall extends Application {
@Override
public void start(Stage primaryStage) {
Circle ball = new Circle(20, 80, 10);
ball.setFill(Color.DARKBLUE);
Pane pane = new Pane(ball);
AnimationTimer timer = new AnimationTimer() {
long lastUpdate = 0 ;
double changeX = 0.1 ;
double changeY = 0 ;
double gravity = 10 ;
double elasticity = 0.95 ;
@Override
public void handle(long now) {
if (lastUpdate == 0) {
lastUpdate = now ;
return ;
}
long elapsedNanos = now - lastUpdate;
double elapsedSeconds = elapsedNanos / 1_000_000_000.0 ;
lastUpdate = now ;
ball.setCenterX(ball.getCenterX() + changeX);
if (ball.getCenterY() + changeY + ball.getRadius() >= pane.getHeight()) {
changeY = - changeY * elasticity;
} else {
changeY = changeY + gravity * elapsedSeconds ;
}
ball.setCenterY(Math.min(ball.getCenterY() + changeY, pane.getHeight() - ball.getRadius()));
}
};
primaryStage.setScene(new Scene(pane, 400, 400));
primaryStage.show();
timer.start();
}
public static void main(String[] args) {
launch(args);
}
}