如何使用等时元素创建JavaFX转换?

时间:2015-07-16 20:11:48

标签: java animation javafx

我正在尝试使用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;会显示正确吗?感谢。

1 个答案:

答案 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);
    }
}