JavaFX动画:随机移动形状(星形)

时间:2015-08-09 22:30:24

标签: animation javafx javafx-8

我的问题是,在每个关键帧之后,矩形的x和y位置应随机变化。 现在只有当我启动程序时,矩形位置是随机设置的,而不是动画本身。

我怎么能这样做,非常感谢...

public class TimeLines extends Application {

private Rectangle rectBasicTimeline;
private Timeline timeline;

@Override
public void start(Stage primaryStage) {
    Button btn = new Button();
    btn.setText("Do Animation");
    int x = new Random().nextInt(500);
    int y = new Random().nextInt(400);
    rectBasicTimeline = new Rectangle(x, y, 100, 50);
    rectBasicTimeline.setFill(Color.RED);

    btn.setOnAction(new EventHandler<ActionEvent>() {

        @Override
        public void handle(ActionEvent event) {

            final Timeline timeline = new Timeline();
            timeline.setCycleCount(Timeline.INDEFINITE);
            timeline.setAutoReverse(true);
            final KeyValue kx = new KeyValue(rectBasicTimeline.xProperty(), x + 200);
            final KeyValue ky = new KeyValue(rectBasicTimeline.yProperty(), y + 200);
            final KeyValue kScale = new KeyValue(rectBasicTimeline.scaleXProperty(), 2);
            final KeyValue kFade = new KeyValue(rectBasicTimeline.opacityProperty(), 0);
            final KeyFrame kf = new KeyFrame(Duration.millis(3000), kx, ky, kScale, kFade);
            timeline.getKeyFrames().add(kf);
            timeline.play();
      }
    });

    AnchorPane root = new AnchorPane();
    root.getChildren().addAll(btn, rectBasicTimeline);
    Scene scene = new Scene(root, 800, 600);
    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    launch(args);
}

}

2 个答案:

答案 0 :(得分:0)

您初始化随机数,因此初始化位置一次,并始终使用它。您需要做的是执行一次动画循环,然后在当前动画结束时创建一个新动画。

示例:

import java.util.Random;

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

public class TimeLines extends Application {

    private Rectangle rectBasicTimeline;

    @Override
    public void start(Stage primaryStage) {
        Button btn = new Button();
        btn.setText("Do Animation");

        int x = new Random().nextInt(500);
        int y = new Random().nextInt(400);
        rectBasicTimeline = new Rectangle(x, y, 100, 50);
        rectBasicTimeline.setFill(Color.RED);

        btn.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {

                play();

            }
        });

        AnchorPane root = new AnchorPane();
        root.getChildren().addAll(btn, rectBasicTimeline);
        Scene scene = new Scene(root, 800, 600);
        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private void play() {

        double x = new Random().nextInt(500);
        double y = new Random().nextInt(400);

        final Timeline timeline = new Timeline();
        // cycle count = 2 because of autoreverse
        timeline.setCycleCount(2);
        timeline.setAutoReverse(true);
        final KeyValue kx = new KeyValue(rectBasicTimeline.xProperty(), x + 200);
        final KeyValue ky = new KeyValue(rectBasicTimeline.yProperty(), y + 200);
        final KeyValue kScale = new KeyValue(rectBasicTimeline.scaleXProperty(), 2);
        final KeyValue kFade = new KeyValue(rectBasicTimeline.opacityProperty(), 0);
        final KeyFrame kf = new KeyFrame(Duration.millis(1000), kx, ky, kScale, kFade);
        timeline.getKeyFrames().add(kf);
        timeline.setOnFinished(e -> {
            // create new animation after this animation finishes
            play();
        });
        timeline.play();

    }

    /**
     * @param args
     *            the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }
}

我不建议采用这种方法,例如: G。当您多次单击该按钮时,会遇到多个时间轴的问题。但我没有任何关于你想要做什么的信息,所以我会留下它。

答案 1 :(得分:0)

我同意@Roland,无需创建多个时间轴。重新点击该按钮只需使用新的KeyFrame重新启动时间轴:

public class StarFall extends Application
{

    private Polygon star;
    private Timeline timeline;
    private final double shs = 5.0; // Star Hand Size
    private final Random random = new Random();


    @Override
    public void start( Stage primaryStage )
    {
        // init shape
        Pos initPos = getRandomPos();
        star = new Polygon();
        star.setLayoutX( initPos.x );
        star.setLayoutY( initPos.y );
        star.setFill( Color.YELLOW );

        // the shape
        star.getPoints().addAll( new Double[]
        {
            0.0, shs * 3,
            shs * 2, shs * 2,
            shs * 3, 0.0,
            shs * 4, shs * 2,
            shs * 6, shs * 3,
            shs * 4, shs * 4,
            shs * 3, shs * 6,
            shs * 2, shs * 4
        } );

        // init timeline
        timeline = new Timeline();
        timeline.setCycleCount( Timeline.INDEFINITE );
        timeline.setAutoReverse( true );

        // init button
        Button btnStart = new Button( "Do Animation" );
        btnStart.setOnAction( ( e ) -> playNextKeyFrame() );

        Button btnStop = new Button( "Stop Animation" );
        btnStop.setLayoutX( 200 );
        btnStart.setLayoutX( 0 );
        btnStop.setOnAction( ( e ) -> timeline.stop() );

        // init scene with root
        AnchorPane root = new AnchorPane( btnStart, btnStop, star );
        Scene scene = new Scene( root, 800, 600 );

        // show
        primaryStage.setScene( scene );
        primaryStage.show();
    }


    private void playNextKeyFrame()
    {
        // generate next random start and end positions for star
        Pos startPos = getRandomPos();
        Pos endPos = getRandomPos();

        // initial values (resetting)
        star.setLayoutX( startPos.x );
        star.setLayoutY( startPos.y );
        star.setScaleX( 1 );
        star.setScaleY( 1 );
        star.setOpacity( 1 );

        // target values
        KeyValue kx = new KeyValue( star.layoutXProperty(), endPos.x );
        KeyValue ky = new KeyValue( star.layoutYProperty(), endPos.y );
        KeyValue kScaleX = new KeyValue( star.scaleXProperty(), 3 );
        KeyValue kScaleY = new KeyValue( star.scaleYProperty(), 3 );
        KeyValue kFade = new KeyValue( star.opacityProperty(), 0.0 );

        // delay animation before start. Use this instead of THread.sleep() !!
        timeline.setDelay( Duration.millis( random.nextInt( 2000 ) + 100 ) );

        // restart timeline with new values
        timeline.stop();
        timeline.getKeyFrames().clear();
        timeline.getKeyFrames().add( new KeyFrame( Duration.millis( 3000 ),
                ( e ) -> playNextKeyFrame(), kx, ky, kFade, kScaleX, kScaleY ) );
        timeline.play();
    }


    private Pos getRandomPos()
    {
        int x = random.nextInt( 500 );
        int y = random.nextInt( 400 );
        Pos p = new Pos();
        p.x = x + 200;
        p.y = y + 200;
        return p;
    }


    private class Pos
    {
        int x;
        int y;
    }


    public static void main( String[] args )
    {
        launch( args );
    }

}