2017-03-15 76 views
0

我正在用JavaFX构建Simon Says游戏。我已经获得了大部分工作,现在唯一的问题是当你运行游戏时,它运行一个for循环来生成颜色,取决于你所在的级别。for循环中的JavaFX TimeLine正在跳过KeyFrames

它似乎显示循环中的一种颜色,但它不会等待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); 

    } 

} 
+0

您不需要发布如此多的代码来演示这一点,您可以创建一个[*最小*示例](https://stackoverflow.com/help/mcve),它仍然是可编译和可运行的,并且仅演示问题在手。这样做可以让您获得更好的答案的机会更大。 – jewelsea

+0

另外:一旦你得到这个工作,我建议你发布整个程序,就像你最初在http://codereview.stackexchange.com上的这个问题中发布的那样,并且让那里的人把它分开并给你如何申请的建议更好的代码标准来提高代码质量。我的猜测是,你会从中学到很多东西。 – jewelsea

+0

@jewelsea我接受了你的建议,并删除了这个问题不需要的所有超额代码。在这一点上,我并不太担心编码标准,一旦我理解了语法背后的逻辑,我会整理它。一旦我有一切工作,我有一个编码标准,我必须解决它遵守。 感谢您的意见! –

回答

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来实现。

+0

这是有道理的。因此,我应该建立一个要运行的转换列表,然后将每个转换存储在SequentialTransition中并运行它? –

+0

所以我使用这个解释,它可能会工作,除了我需要存储特定颜色动画的多个实例。现在,当我运行我会得到一个重复的孩子错误。 –

+0

然后创建新的实例,它们不会重复。 – jewelsea