7 Replies Latest reply: Jun 5, 2011 1:15 AM by Darryl Burke RSS

    Sequentially blinking images

    866298
      I'm trying to create some kind of Simon game (like Mattel's) in JavaFX. There are some nodes in the scene that should blink in in a certain growing sequence: [1] [1,0] [1,0,2]... indexes are just random, adding one to the sequence on each round (just as in Simon)

      So I'm trying the following code to create the animated sequence of blinking nodes:
          simon.prepareNextRound();
          var sequenceLength : Integer = simon.current_level;
      
          var roundTimeline = Timeline {
             repeatCount : sequenceLength
             keyFrames: [
                 KeyFrame {
                      time: 0s
                      action: function () {
                         var currentNode : Node;
      
                         // getNextClue returns the next light index in the sequence
                         var index = simon.getNextClue();
                         currentNode = light0;
                         if (index == 1)
                              currentNode = light1;
                         if (index == 2)
                              currentNode = light2;
      
                         FadeTransition {
                           duration: 0.25s
                           node : currentNode
                           fromValue: 1.0 toValue: 0.0
                           repeatCount: 2
                           autoReverse : true
                           }.playFromStart();
                      }
                  }
                  KeyFrame{
                      time: 1s
                  }
      
              ]
          }
      The problem is it works... but sometimes two lights blink at the same time or they just don't blink. I just don't understand why. I must be missing something about Timelines, or I'm just using the wrong tool (timelines, that is). How would you do it instead of using Timelines?
        • 1. Re: Sequentially blinking images
          866298
          I've also tried creating transitions externaly. One transition for each image, like this:
          var image0BlinkTransition :FadeTransition = FadeTransition {
                               duration: 0.25s
                               node : image0
                               fromValue: 1.0 toValue: 0.0
                               repeatCount: 2
                               autoReverse : true
                               }
          so the timeline is simplified to
           var roundTimeline = Timeline {
                 repeatCount : sequenceLength
                 keyFrames: [
                     KeyFrame {
                          time: 0s
                          action: function () {
                             // getNextClue returns the next light index in the sequence
                             var index = simon.getNextClue();
                             if (index == 0)
                                  image0BlinkTransition.playFromStart();
                             if (index == 1)
                                  image1BlinkTransition.playFromStart();
                             if (index == 2)
                                  image2BlinkTransition.playFromStart();                  
                          }
                      }
                      KeyFrame{
                          time: 1s
                      }
                  ]
              }
          But the same behaviour is observed. Sometimes it works flawlessly, sometimes images blink at the wrong moment or they don't at all.
          • 2. Re: Sequentially blinking images
            jojorabbit
            Hi,
            i see that u use 1.3 JavaFX. I did not worked with it for a long time and i don`t have it on this cpu, but i think something like this shall work just try to transfer Java code to script code. Use only one timeline with generated keyframes just change keyframes on gamecycle.
            Instead of ObservableList use Sequence, i guess maybe that error is because all keyframes have same duration so maybe they start at the same time.
               private ObservableList<KeyFrame> generateKeyFrames() {
                    ObservableList<KeyFrame> frames = FXCollections.<KeyFrame>observableArrayList();
                    ObservableList<Integer> indexes = generateIndexes();
                    double duration = 250;
                    double dx = 250;
                    count = 1;
                    for (int index : indexes) {
                        final Node node = localHBox.getChildren().get(index);
                        // keyframe fadeout
                        final KeyFrame keyFrame1 = new KeyFrame(
                                Duration.valueOf(duration),
                                index + "_keyframe1",
                                new EventHandler<ActionEvent>() {
            
                                    public void handle(ActionEvent event) {
                                        KeyFrame source = (KeyFrame) event.getSource();
                                        System.out.println(source.getName() + " finished. " + source.getTime());
                                    }
                                },
                                new KeyValue(node.opacityProperty(), 0.0d, Interpolator.LINEAR));
            
                        duration += dx;
                        // keyframe fadeIn
                        final KeyFrame keyFrame2 = new KeyFrame(
                                Duration.valueOf(duration),
                                index + "_keyframe2",
                                new EventHandler<ActionEvent>() {
            
                                    public void handle(ActionEvent event) {
                                        KeyFrame source = (KeyFrame) event.getSource();
                                        System.out.println(source.getName() + " finished " + source.getTime());
                                    }
                                },
                                new KeyValue(node.opacityProperty(), 1.0d, Interpolator.LINEAR));
                        duration += dx;
                        frames.addAll(keyFrame1, keyFrame2);
                    }
                    System.out.println("frames: " + frames.size());
                    return frames;
                }
            
                private ObservableList<Integer> generateIndexes() {
                    ObservableList<Integer> list = FXCollections.<Integer>observableArrayList();
                    Random intGenerator = new Random();
                    for (int i = 0; i < currentLevel; i++) {
                        list.add(intGenerator.nextInt(4));
                    }
                    System.out.println("index: " + list);
                    return list;
                }
            Hope it helps.

            Edited by: jojorabbit on Jun 3, 2011 2:15 PM
            • 3. Re: Sequentially blinking images
              866298
              Thank you. Yes, it's Java1.3 because I need to work on a Mac.

              Your solution seems so complex for such a relatively simple task! Something I would do with a coroutine or a loop with a function for pausing execution on another language can't certainly be so complicated! Or is it?

              Nevertheless, keyframes are not starting at the same time. My timeline repeats itself sequenceLength times. But each time it gets a new index from simon.getNextClue(), runs the transition and -ideally-, completes the timeline execution before the next timeline cycle.

              Nevertheless, I'll have a look at your KeyFrame building method.
              • 4. Re: Sequentially blinking images
                866298
                I MAY have solved it by creating a sequence of KeyFrames and a Timeline using their constructors and properties, like this:
                    function playSimonRound() {
                        simon.prepareNextRound();
                
                        var sequenceLength : Integer = simon.current_level;
                        
                        // Create a sequence of keyFrames, so we may set their time programmatically
                
                        var keyFrameSequence : KeyFrame[] = [];
                        for ( i in [0..sequenceLength-1]) {
                            var index = simon.getNextClue();
                
                            var keyFrame : KeyFrame = KeyFrame{
                                time : Duration.valueOf(1000 + i * 1000);
                                action: function() {
                                    if (index == 0)
                                        blinkImage0Transition.playFromStart();
                                    if (index == 1)
                                         blinkImage1Transition.playFromStart();
                                    if (index == 2)
                                         blinkImage1Transition.playFromStart();
                                }
                            }
                
                            insert keyFrame into keyFrameSequence;
                        }
                
                        //Add the sequence to the timeline and play it.
                
                        var roundTimeline = Timeline {};
                        roundTimeline.keyFrames = keyFrameSequence;
                
                        fadeSimonInTransition.playFromStart();
                        roundTimeline.playFromStart();
                  }
                Edited by: Notnasiul on 03-jun-2011 9:03

                Edited by: Notnasiul on 03-jun-2011 9:04
                • 5. Re: Sequentially blinking images
                  jojorabbit
                  Hi,
                  it is not so complex just 2 functions,
                  first generates list with keyframes other indexes.
                  With those 2 functions i can have up to n images in game currently there are 4.
                  In yours i see only 3 images and one possible error.
                  if (index == 0)
                     blinkImage0Transition.playFromStart(); // -> image 0 blink, index = 0
                  if (index == 1)
                     blinkImage1Transition.playFromStart();  // -> image 1 blink, index = 1
                  if (index == 2)
                     blinkImage1Transition.playFromStart(); // *image 1 blink, index = 2 (is this error or it should blink image1 on index 2?)*
                  I am glad that u solved it.

                  Here is the whole code with comments maybe it will help u more.
                  Hope it helps and that it is not so complicated.
                  I have not implemented game logic i will leave that for you.
                  import java.util.Random;
                  import javafx.animation.Interpolator;
                  import javafx.animation.KeyFrame;
                  import javafx.animation.KeyValue;
                  import javafx.animation.Timeline;
                  import javafx.application.Application;
                  import javafx.collections.FXCollections;
                  import javafx.collections.ObservableList;
                  import javafx.event.ActionEvent;
                  import javafx.event.EventHandler;
                  import javafx.scene.Group;
                  import javafx.scene.Node;
                  import javafx.scene.Scene;
                  import javafx.scene.control.Button;
                  import javafx.scene.layout.HBox;
                  import javafx.scene.paint.Color;
                  import javafx.scene.shape.Rectangle;
                  import javafx.stage.Stage;
                  import javafx.util.Duration;
                  
                  public class SimonGame extends Application {
                  
                      private Scene scene;
                      private Group root;
                      private HBox localHBox;
                      private int currentLevel = 1;
                      private Timeline timeline;
                      private int nodeCount = 4; // count of blinking nodes -> can be used for differend levels easy(4 items)/normal(5 items)/hard(6 items) etc 
                      private ObservableList<Rectangle> items = FXCollections.observableArrayList();
                  
                      public static void main(String[] args) {
                          Application.launch(SimonGame.class, args);
                      }
                  
                      @Override
                      public void start(Stage primaryStage) throws Exception {
                          createItems();
                          timeline = new Timeline();
                          timeline.setCycleCount(1);
                          timeline.setOnFinished(new EventHandler<ActionEvent>() {
                  
                              public void handle(ActionEvent event) {
                                  // update lvl
                                  System.out.println("timeline finished.");
                                  currentLevel++;
                                  System.out.println("status: " + timeline.getStatus());
                              }
                          });
                  
                          root = new Group();
                          scene = new Scene(root, 400, 400, Color.WHITE);
                          setupCSS();
                          primaryStage.setScene(scene);
                          //
                          //
                          localHBox = new HBox(10);
                          localHBox.getChildren().addAll(items);
                  
                          localHBox.setTranslateX(100);
                          localHBox.setTranslateY(100);
                          // button to run animation
                          final Button button = new Button("animate");
                          button.setTranslateX(160);
                          button.setTranslateY(180);
                          button.setOnAction(new EventHandler<ActionEvent>() {
                  
                              public void handle(ActionEvent event) {
                                  timeline.getKeyFrames().setAll(generateKeyFrames());
                                  timeline.playFromStart();
                              }
                          });
                          //
                          root.getChildren().addAll(localHBox, button);
                          primaryStage.centerOnScreen();
                          primaryStage.setVisible(true);
                      }
                  
                      protected void setupCSS() {
                      }
                  
                      /***
                       * Method for creating "blinking items"
                       * Rectangles in this case with random color
                       */
                      private void createItems() {        
                          Random colorRandomizer = new Random();
                          for (int i = 0; i < nodeCount; i++) {
                              // maybe for hardest level make colors that are close and similar
                              // for example: red, dark red, light red etc
                              Rectangle rect = new Rectangle(50, 50,
                                      Color.color(
                                      colorRandomizer.nextDouble(),
                                      colorRandomizer.nextDouble(),
                                      colorRandomizer.nextDouble()));
                              items.add(rect);
                          }
                      }
                  
                      /***
                       * Method for generating "blinking" KeyFrames
                       * @return List/Sequence filled with KeyFrames
                       */
                      private ObservableList<KeyFrame> generateKeyFrames() {
                          // List with frames
                          ObservableList<KeyFrame> frames = FXCollections.<KeyFrame>observableArrayList();
                          // indexes
                          ObservableList<Integer> indexes = generateIndexes();
                          double duration = 250;
                          double dx = 250;
                          // for each index in indexes create fadeOut/fadeIn keyframes
                          for (int index : indexes) {
                              final Node node = localHBox.getChildren().get(index);
                              // keyframe fadeout
                              final KeyFrame keyFrame1 = new KeyFrame(
                                      Duration.valueOf(duration),
                                      index + "_keyframe1", // name of keyframe
                                      new EventHandler<ActionEvent>() { // handler just for debug
                  
                                          public void handle(ActionEvent event) {
                                              KeyFrame source = (KeyFrame) event.getSource();
                                              System.out.println(source.getName() + " finished. " + source.getTime());
                                          }
                                      },
                                      new KeyValue(node.opacityProperty(), 0.0d, Interpolator.LINEAR));
                              
                              // incrase duration
                              duration += dx;
                              // keyframe fadeIn
                              final KeyFrame keyFrame2 = new KeyFrame(
                                      Duration.valueOf(duration),
                                      index + "_keyframe2", // name of keyframe
                                      new EventHandler<ActionEvent>() { // handler just for debug
                  
                                          public void handle(ActionEvent event) {
                                              KeyFrame source = (KeyFrame) event.getSource();
                                              System.out.println(source.getName() + " finished " + source.getTime());
                                          }
                                      },
                                      new KeyValue(node.opacityProperty(), 1.0d, Interpolator.LINEAR));
                              // incrase duration
                              duration += dx;
                              // add frame to list
                              frames.addAll(keyFrame1, keyFrame2);
                          }
                          // printing to console just for debug
                          System.out.println("frames: " + frames.size());
                          return frames;
                      }
                  
                      /***
                       * Method for generating indexes for blinking
                       * @return List/Sequence with indexes
                       */
                      private ObservableList<Integer> generateIndexes() {
                          ObservableList<Integer> list = FXCollections.<Integer>observableArrayList();
                          Random intGenerator = new Random();
                          // number of indexes in list depends on current level of game
                          for (int i = 0; i < currentLevel; i++) {
                              list.add(intGenerator.nextInt(nodeCount));
                          }
                          // printing to console just for debug
                          System.out.println("index: " + list);
                          return list;
                      }
                  }
                  • 6. Re: Sequentially blinking images
                    866298
                    jojorabbit wrote:
                    blinkImage1Transition.playFromStart(); // image 1 blink, index = 2 (is this error or it should blink image1 on index 2?)
                    Nay, don't worry. It was just an example, I should have removed that line. There will be just five images, so I guess it's way easier just adding their lines one by one. But thank you a lot for your help, it was the key for the solution!
                    • 7. Re: Sequentially blinking images
                      Darryl Burke
                      Moderator advice: If your question is answered, please mark it as such. Don't forget to identify 'Correct' and 'Helpful' posts.

                      db