2017-03-15 63 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