for循环中的JavaFX TimeLine正在跳过KeyFrames

时间:2017-03-15 21:36:23

标签: java javafx timeline

我正在JavaFX中构建一个Simon Says游戏。我已经完成了大部分工作,我现在唯一的问题是当你运行游戏时它运行for循环以根据你所处的级别生成颜色。

它似乎从循环中显示一种颜色,但在它飞过循环的其余部分并存储值之前,它不会等待KeyFrame完成。如何使循环等待KeyFrame完成,以便显示所有颜色变化?

package assign3;

import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

import javafx.animation.FillTransition;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.SequentialTransition;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.Duration;

public class Question2 extends Application
{

    public static final int RED = 1;
    public static final int GREEN = 2;
    public static final int BLUE = 3;
    public static final int ORANGE = 4;
    private int thisGameScore = 0;
    private int level = 1;
    private BorderPane obBorder;
    private HBox obPane;
    private HBox obStart;
    private Timeline tlRed;
    private Timeline tlBlue;
    private Timeline tlGreen;
    private Timeline tlOrange;
    private SequentialTransition stList = new SequentialTransition();
    private Button btStart;
    private ArrayList<Integer> colours;
    private ArrayList<Integer> guesses;

    @Override
    public void start( Stage obPrimeStage ) throws Exception
    {        
        boolean runGame = true;
        int guessIndex = 0;
        obBorder = new BorderPane();
        obPane = new HBox();
        obStart = new HBox();
        Button btRed = new Button("Red");
        Button btGreen = new Button("Green");
        Button btBlue = new Button("Blue");
        Button btOrange = new Button("Orange");
        btStart = new Button("Start");
        class RedTimeLine
        {
            Timeline tlRed;
            RedTimeLine()
            {
                tlRed = new Timeline();
                tlRed.getKeyFrames().add(new KeyFrame(Duration.ZERO, 
                        new KeyValue(obBorder.backgroundProperty(),
                                new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY)))));
                tlRed.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
                        new KeyValue(obBorder.backgroundProperty(),
                                new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
            }

        }
        tlBlue = new Timeline();
        tlBlue.getKeyFrames().add(new KeyFrame(Duration.ZERO, 
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)))));
        tlBlue.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
        tlGreen = new Timeline();
        tlGreen.getKeyFrames().add(new KeyFrame(Duration.ZERO, 
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.GREEN, CornerRadii.EMPTY, Insets.EMPTY)))));
        tlGreen.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));
        tlOrange = new Timeline();
        tlOrange.getKeyFrames().add(new KeyFrame(Duration.ZERO, 
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.ORANGE, CornerRadii.EMPTY, Insets.EMPTY)))));
        tlOrange.getKeyFrames().add(new KeyFrame(Duration.seconds(1),
                new KeyValue(obBorder.backgroundProperty(),
                        new Background(new BackgroundFill(Color.TRANSPARENT, CornerRadii.EMPTY, Insets.EMPTY)))));


        obStart.getChildren().add(btStart);
        obPane.getChildren().addAll(btRed, btGreen, btBlue, btOrange);
        obBorder.setCenter(obPane);
        obBorder.setBottom(obStart);
        obPane.setAlignment(Pos.CENTER);
        obStart.setAlignment(Pos.CENTER);

        Scene obScene = new Scene(obBorder, 400, 400);

        obPrimeStage.setTitle("Simon Says");
        obPrimeStage.setScene(obScene);
        obPrimeStage.show();



        btStart.setOnAction((ActionEvent start) -> {
            colours = new ArrayList<>();
            guesses = new ArrayList<>();
            obChange.handle(start);
            stList.play();
            System.out.println("Started new game");

        });  


        btRed.setOnAction((ActionEvent e) -> 
        {
            guesses.add(RED);
            if(guesses.get(guessIndex) != colours.get(guessIndex) )
            {
                obStart.getChildren().add(btStart);
                level = 1;
            }
            else
            {
                if(guesses.size() == colours.size())
                {
                    level += 1;
                    colours = new ArrayList<>();
                    guesses = new ArrayList<>();
                    for(int i = 0; i < level; i++)
                    {
                        obChange.handle(e);
                    }
                    stList.play();
                }
            }
        });

        btGreen.setOnAction((ActionEvent e) -> 
        {

            guesses.add(GREEN);
            if(guesses.get(guessIndex) != colours.get(guessIndex) )
            {
                obStart.getChildren().add(btStart);
                level = 1;
            }
            else
            {
                if(guesses.size() == colours.size())
                {
                    level += 1;
                    colours = new ArrayList<>();
                    guesses = new ArrayList<>();
                    for(int i = 0; i < level; i++)
                    {
                        obChange.handle(e);
                    }
                    stList.play();
                }
            }
        });

        btBlue.setOnAction((ActionEvent e) -> 
        {

            guesses.add(BLUE);
            if(guesses.get(guessIndex) != colours.get(guessIndex) )
            {
                obStart.getChildren().add(btStart);
                level = 1;
            }
            else
            {
                if(guesses.size() == colours.size())
                {
                    level += 1;
                    colours = new ArrayList<>();
                    guesses = new ArrayList<>();
                    for(int i = 0; i < level; i++)
                    {
                        obChange.handle(e);
                    }
                    stList.play();
                }
            }
        });

        btOrange.setOnAction((ActionEvent e) -> 
        {

            guesses.add(ORANGE);
            if(guesses.get(guessIndex) != colours.get(guessIndex) )
            {
                obStart.getChildren().add(btStart);
                level = 1;

            }
            else
            {
                if(guesses.size() == colours.size())
                {
                    level += 1;
                    guesses = new ArrayList<>();
                    for(int i = 0; i < level; i++)
                    {
                        obChange.handle(e);
                    }
                    stList.play();
                }
            }
        });

    }



    class ChangeColour implements EventHandler<ActionEvent>
    {

        @Override
        public void handle( ActionEvent arg0 )
        {
            thisGameScore = 0;
            int randomColour = (int)((Math.random() * 4) + 1);

            if(randomColour == RED)
            {
                colours.add(RED);
                stList.getChildren().add(new RedTimeLine());

            }
            else if(randomColour == BLUE)
            {
                colours.add(BLUE);
                stList.getChildren().add(tlBlue);

            }
            else if(randomColour == GREEN)
            {
                colours.add(GREEN);
                stList.getChildren().add(tlGreen);

            }
            else if(randomColour == ORANGE)
            {
                colours.add(ORANGE);
                stList.getChildren().add(tlOrange);

            }
            obStart.getChildren().remove(btStart);


        }

    }

    ChangeColour obChange = new ChangeColour();




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

    }

}

1 个答案:

答案 0 :(得分:0)

我想我会做这样的事情:

public void playSequence(int sequenceLength, double speed) {
    Timeline timeline = new Timeline();

    for (int i = 0; i < sequenceLength; i++) {
        Color color = colors[random.nextInt(colors.length)];
        Segment segment = segmentMap.get(color);

        timeline.getKeyFrames().addAll(
                new KeyFrame(
                        Duration.seconds(i), new KeyValue(segment.litProperty(), true)
                ),
                new KeyFrame(
                        Duration.seconds(i + 0.9), new KeyValue(segment.litProperty(), false)
                )
        );

        isPlaying.set(true);
        timeline.setOnFinished(event -> isPlaying.set(false));
        timeline.setRate(speed);
        timeline.play();
    }
}

上面的示例使用时间轴,每个段点亮的开始时间会变化,以便依次点亮每个段。

完整样本

simon

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.*;
import javafx.scene.control.Button;
import javafx.scene.effect.ColorAdjust;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import static javafx.scene.paint.Color.*;

public class SimpleSimon extends Application {
    private int sequenceLength = 1;
    private int speed = 1;

    @Override 
    public void start(Stage stage) throws Exception {
        Simon simon = new Simon();

        Button play = new Button("Play");
        play.setStyle("-fx-font-size: 20px;");
        play.disableProperty().bind(simon.isPlayingProperty());
        play.setOnAction(event -> {
            simon.playSequence(sequenceLength, speed);
            sequenceLength++;
            speed *= 1.05;
        });

        VBox layout = new VBox(10, simon, play);
        layout.setPadding(new Insets(10));
        layout.setAlignment(Pos.CENTER);

        stage.setScene(new Scene(layout));
        stage.show();
    }

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

class Simon extends Group {
    private static final Random random = new Random(42);

    private final Color[] colors = {
            RED, GREEN, BLUE, ORANGE
    };

    private Map<Color, Segment> segmentMap = new HashMap<>();

    private ReadOnlyBooleanWrapper isPlaying = new ReadOnlyBooleanWrapper();

    public Simon() {
        for (int i = 0; i < colors.length; i++) {
            Segment segment = new Segment(colors[i], i * 90);
            getChildren().add(segment);
            segmentMap.put(colors[i], segment);
        }
    }

    public void playSequence(int sequenceLength, double speed) {
        Timeline timeline = new Timeline();

        for (int i = 0; i < sequenceLength; i++) {
            Color color = colors[random.nextInt(colors.length)];
            Segment segment = segmentMap.get(color);

            timeline.getKeyFrames().addAll(
                    new KeyFrame(
                            Duration.seconds(i), new KeyValue(segment.litProperty(), true)
                    ),
                    new KeyFrame(
                            Duration.seconds(i + 0.9), new KeyValue(segment.litProperty(), false)
                    )
            );
        }

        isPlaying.set(true);
        timeline.setOnFinished(event -> isPlaying.set(false));
        timeline.setRate(speed);
        timeline.play();
    }

    public boolean isPlaying() {
        return isPlaying.get();
    }

    public ReadOnlyBooleanWrapper isPlayingProperty() {
        return isPlaying;
    }
}

class Segment extends Arc {
    private BooleanProperty lit = new SimpleBooleanProperty();
    private static final double RADIUS = 100;

    private static final ColorAdjust litEffect = new ColorAdjust(0, 0, 0.5, 0);
    private static final ColorAdjust unlitEffect = new ColorAdjust(0, 0, 0, 0);

    public Segment(Color color, double angleOffset) {
        super(RADIUS, RADIUS, RADIUS, RADIUS,  angleOffset, 90);
        setFill(color);
        setType(ArcType.ROUND);

        setEffect(unlitEffect);
        lit.addListener((observable, oldValue, newValue) ->
                setEffect(lit.get() ? litEffect : unlitEffect)
        );
    }

    public void setLit(boolean lit) {
        this.lit.set(lit);
    }

    public boolean isLit() {
        return lit.get();
    }

    public BooleanProperty litProperty() {
        return lit;
    }
}

通过SequentialTransition可以实现类似的效果。