title: Motion issues with ParallelTransition´s Event Handler in JavaFx 8
body: <p>I am working on a College project in javafx: a Game like Space Invaders.I was trying to make The animation of each ovni with a <strong>ParallelTransition</strong>, creating a <strong>TimeLine</strong> animation and adding it to the ParallelTransition for each of them, managing a EventHandler for each of them in order to move the ovni in X position and moving in Y when it comes to the left bound of the window.The issue is that when i am playing the animation, only the first row moves correctly in x position, but the other rows don´t. In other words, when the other rows move some distance on x position, they don´t finish their motion on the rigth bound,but they move in Y position instead.Resulting of something like that:<a href="https://i.stack.imgur.com/l3PUQ.png" rel="nofollow noreferrer"></a></p>
  
  <p>This is the method to buildOvni:</p>
  
  <pre><code>public Shape buildOvni(){
      Arc arcCuerpo=new Arc(Constantes.POS_CUERPO_OVNI_X,Constantes.POS_CUERPO_OVNI_Y,Constantes.ANCHO_CUERPO_OVNI,Constantes.ALTO_CUERPO_OVNI,0,180);
      Arc arcL=new Arc(Constantes.POS_ARC_IZQ_X,Constantes.POS_ARC_IZQ_Y,Constantes.ANCHO_ARC_IZQ,Constantes.ALTO_ARC_IZQ,180,180);
      Arc arcCentro=new Arc(Constantes.POS_ARC_CTR_X,Constantes.POS_ARC_CTR_Y,Constantes.ANCHO_ARC_CTR,Constantes.ALTO_ARC_CTR,180,180);
      Arc arcD=new Arc(Constantes.POS_ARC_DER_X,Constantes.POS_ARC_DER_Y,Constantes.ANCHO_ARC_DER,Constantes.ALTO_ARC_DER,180,180);
      Shape union1=Shape.union(arcCuerpo, arcL);
      Shape union2=Shape.union(union1, arcCentro);
      Shape union3=Shape.union(union2, arcD);
  
      return union3;
  }
  </code></pre>
  
  <p>Secondly, I have declared two matrix for ovnis: one for Panes that will contain each ovni´s shape; and other that will contains the ovni objects.</p>
  
  <pre><code>  public Juego(){
      lab=new Label();
      transicionEnY=new ParallelTransition();
      dir=new File(Constantes.GAME_BACKGROUND);
      Pane navePane=new Pane();
      paneOvnis=new Pane[3][6]; //the panes for each ovni´s shape
      nave=new Nave(navePane);
      gameContainer=new Pane();
      gameContainer.getChildren().addAll(navePane);
      background=new Image(dir.toURI().toString());
      pane=new BorderPane();
      pane.setCenter(gameContainer);
      pane.setBackground(new Background(new BackgroundImage(background,null,null,null,new BackgroundSize(Constantes.MAXIMUM_WIDHT,Constantes.MAXIMUM_HEIGTH,false,false,false,true))));
      //playMusic();
      agregarOvnis();
      moverOvnis();
     pane.setBottom(lab);
  }
  </code></pre>
  
  <p>The method to populate each matrix:</p>
  
  <pre><code>public void agregarOvnis(){
      this.ovnis=new Ovni[paneOvnis.length][paneOvnis[0].length];
      for(int i=0;i&lt;paneOvnis.length;i++){
          for(int j=0;j&lt;paneOvnis[0].length;j++){    
              Pane paneOvni=new Pane();
              Ovni ovni=new OvniGris(paneOvni);
              ovni.setLocation(Constantes.POS_OVNI_X+Constantes.OVNI_SPACING_X*j,Constantes.POS_OVNI_Y+Constantes.OVNI_SPACING_Y*i);
              this.gameContainer.getChildren().add(paneOvni);
              this.paneOvnis[i][j]=paneOvni;
              this.ovnis[i][j]=ovni;
          }
      }
  }
  </code></pre>
  
  <p>The method that make declare the ParallelTransition and make TimeLine animations for each ovni:</p>
  
  <pre><code>    public void moverOvnis(){
      ParallelTransition animaciones=new ParallelTransition();
      for(int i=0;i&lt;ovnis.length;i++){
          for(int j=0;j&lt;ovnis[i].length;j++){
              Timeline animacionOvnis=new Timeline();
              KeyFrame kf=new KeyFrame(Duration.millis(900),new ManejadorMovimientos(i,j));
              animacionOvnis.getKeyFrames().add(kf);
              animacionOvnis.setCycleCount(Timeline.INDEFINITE);
              animacionOvnis.setAutoReverse(false);
              animaciones.getChildren().add(animacionOvnis);
          }
      }
      animaciones.play();
  }
  </code></pre>
  
  <p>Finally, this is the TimeLine EventHandler class to make the ovni motion for each ovni:</p>
  
  <pre><code>private class ManejadorMovimientos implements EventHandler&lt;ActionEvent&gt;{
  
      int i;
      int j;
      int orientacion=1;
  
      public ManejadorMovimientos(int i, int j){
          this.i=i;
          this.j=j;
      }
  
      @Override
      public void handle(ActionEvent event) {
          double distanciaMaxDer=maxDistanceRight();
          double distanciaMaxIzq=maxDistanceLeft();
          lab.setText(""+distanciaMaxDer+","+ovnis[0][5].getXLocation());
          if(orientacion==1)
             if(distanciaMaxDer-30&gt;0){ 
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation()+30,ovnis[i][j].getYLocation());
             }
             else{
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);   
              orientacion=-1;                
             }
          else{
             if(distanciaMaxIzq-30&gt;30){ 
             ovnis[i][j].setLocation(ovnis[i][j].getXLocation()-30,ovnis[i][j].getYLocation());
             }
             else{
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
              orientacion=1;
             }
          }
  
      }
  
      private double maxDistanceRight(){
          int j=ovnis[0].length-1;
          while(j&gt;=0){
              for(int i=0;i&lt;ovnis.length;i++){
                  if(ovnis[i][j]!=null){
                      return 1.25*Constantes.MAXIMUM_WIDHT-ovnis[i][j].getXLocation();
                  }
              }
              j--;
          }
          return -1;
      }
  
      private double maxDistanceLeft(){
          int j=0;
          while(j&lt;ovnis[0].length){
              for(int i=0;i&lt;ovnis.length;i++){
                  if(ovnis[i][j]!=null){
                      return ovnis[i][j].getXLocation()-30;
                  }
              }
              j++;
          }
          return -1;
      }
  
  }
  </code></pre>
  
  <p>I leave here the Constants,Ovni and Game Class,respectively, for more information (Sorry for some words in spanish,it´s part of the requeriments of my project.)</p>
  
  <p><strong>Constants Class</strong></p>
  
  <pre><code>    public class Constantes {
  
  //PARAMETROS GENERALES DEL JUEGO
  public static final double MENU_HEIGTH= 600;
  public static final double MENU_WIDTH=  500;
  public static final double MAXIMUM_HEIGTH = 800;
  public static final double MAXIMUM_WIDHT= 640;
  public static final String MAIN_LOGO="src/backgrounds/logo.png";
  public static final String MAIN_BACKGROUND="src/backgrounds/mainbackground2.jpg";
  public static final String GAME_BACKGROUND="src/backgrounds/gamebackground2.jpg";
  public static final String GAME_BACKGROUND_MUSIC="src/sounds/game.mp3";
  public static final String MAIN_BACKGROUND_MUSIC="src/sounds/main.mp3";
  
  //PARAMETROS DE CONSTRUCCION DE LA NAVE
  public static final double POS_NAVE_X=MAXIMUM_WIDHT/2;
  public static final double POS_NAVE_Y=MAXIMUM_HEIGTH-295;
  public static final double ANCHO_REC_A=50;
  public static final double ALTO_REC_A=18;
  public static final double POS_REC_A_X=(POS_NAVE_X/4)-(ANCHO_REC_A/2);
  public static final double POS_REC_A_Y=POS_NAVE_Y-400;
  public static final double ANCHO_REC_B=ANCHO_REC_A*0.66667;
  public static final double ALTO_REC_B=10;
  public static final double POS_REC_B_X=POS_REC_A_X+ANCHO_REC_B/4;
  public static final double POS_REC_B_Y=POS_NAVE_Y-405;
  public static final double ANCHO_REC_C=ANCHO_REC_B*0.225;
  public static final double ALTO_REC_C=10;
  public static final double POS_REC_C_X=POS_REC_B_X+ANCHO_REC_B/2;
  public static final double POS_REC_C_Y=POS_REC_B_Y;
  public static final double ANCHO_REC_D=ANCHO_REC_C*0.45;
  public static final double ALTO_REC_D=10;
  public static final double POS_REC_D_X=POS_REC_C_X-1;
  public static final double POS_REC_D_Y=POS_REC_C_Y-ALTO_REC_C-ALTO_REC_D+ALTO_REC_C/2;
  
  
  //PARAMETROS DE CONSTRUCCION DEL OVNI
  public static final double POS_OVNI_X=70;
  public static final double POS_OVNI_Y=40;
  public static final double POS_CUERPO_OVNI_X=0;
  public static final double POS_CUERPO_OVNI_Y=0;
  public static final double ANCHO_CUERPO_OVNI=23;
  public static final double ALTO_CUERPO_OVNI=15;
  public static final double ANCHO_ARC_IZQ=ANCHO_CUERPO_OVNI*0.22;
  public static final double ALTO_ARC_IZQ=ALTO_CUERPO_OVNI*0.55;
  public static final double POS_ARC_IZQ_X=POS_CUERPO_OVNI_X - ANCHO_CUERPO_OVNI * 0.80 + ANCHO_ARC_IZQ / 2;
  public static final double POS_ARC_IZQ_Y=POS_CUERPO_OVNI_Y;
  public static final double ANCHO_ARC_CTR=ANCHO_CUERPO_OVNI*0.35;
  public static final double ALTO_ARC_CTR=ALTO_CUERPO_OVNI*0.30;
  public static final double POS_ARC_CTR_X=POS_CUERPO_OVNI_X;
  public static final double POS_ARC_CTR_Y=POS_CUERPO_OVNI_Y;
  public static final double ANCHO_ARC_DER=ANCHO_CUERPO_OVNI*0.22;
  public static final double ALTO_ARC_DER=ALTO_CUERPO_OVNI*0.55;
  public static final double POS_ARC_DER_X=POS_CUERPO_OVNI_X + ANCHO_CUERPO_OVNI * 0.60 + ANCHO_ARC_DER / 2;
  public static final double POS_ARC_DER_Y=POS_CUERPO_OVNI_Y;
  public static final double POS_OVNI_WINDOW_X=POS_CUERPO_OVNI_X - ANCHO_CUERPO_OVNI * 0.80;
  public static final double POS_OVNI_WINDOW_Y=POS_CUERPO_OVNI_Y - ANCHO_CUERPO_OVNI / 2;
  public static final double OVNI_SPACING_X=70;
  public static final double OVNI_SPACING_Y=30;
  
  //PARAMETROS DE MOVIMIENTO NAVE
  public static final double MOVIMIENTO_NAVE=2;
  
  //PARAMETROS DE MOVIMIENTO OVNI
  </code></pre>
  
  <p>}</p>
  
  <p><strong>OVNI Class</strong></p>
  
  <pre><code>public abstract class Ovni {
  protected Shape ovni;
  
  public Ovni(Pane pane){
      ovni=buildOvni();
      pane.getChildren().add(ovni);
  }
  
  public void setLocation(double x,double y){
      ovni.setLayoutX(x);
      ovni.setLayoutY(y);
  }
  
  public double getXLocation(){
     return ovni.getLayoutX();
  }
  
  public double getYLocation(){
     return ovni.getLayoutY();
  }
  
  public Shape getOvni() {
      return ovni;
  }
  
  public void setOvni(Shape ovni) {
      this.ovni = ovni;
  }
  
  public Shape buildOvni(){
      Arc arcCuerpo=new Arc(Constantes.POS_CUERPO_OVNI_X,Constantes.POS_CUERPO_OVNI_Y,Constantes.ANCHO_CUERPO_OVNI,Constantes.ALTO_CUERPO_OVNI,0,180);
      Arc arcL=new Arc(Constantes.POS_ARC_IZQ_X,Constantes.POS_ARC_IZQ_Y,Constantes.ANCHO_ARC_IZQ,Constantes.ALTO_ARC_IZQ,180,180);
      Arc arcCentro=new Arc(Constantes.POS_ARC_CTR_X,Constantes.POS_ARC_CTR_Y,Constantes.ANCHO_ARC_CTR,Constantes.ALTO_ARC_CTR,180,180);
      Arc arcD=new Arc(Constantes.POS_ARC_DER_X,Constantes.POS_ARC_DER_Y,Constantes.ANCHO_ARC_DER,Constantes.ALTO_ARC_DER,180,180);
      Shape union1=Shape.union(arcCuerpo, arcL);
      Shape union2=Shape.union(union1, arcCentro);
      Shape union3=Shape.union(union2, arcD);
  
      return union3;
  }
  </code></pre>
  
  <p>}</p>
  
  <p>GAME class</p>
  
  <pre><code>public class Juego {
  private BorderPane pane;
  private Pane gameContainer;
  private File dir;
  private Image background;
  private MediaPlayer player;
  private Nave nave;
  private Pane[][] paneOvnis;
  private Ovni[][] ovnis;
  private final ParallelTransition transicionEnY;
  Label lab;
  /**
   *
   */
  public Juego(){
      lab=new Label();
      transicionEnY=new ParallelTransition();
      dir=new File(Constantes.GAME_BACKGROUND);
      Pane navePane=new Pane();
      paneOvnis=new Pane[3][6];
      nave=new Nave(navePane);
      gameContainer=new Pane();
      gameContainer.getChildren().addAll(navePane);
      background=new Image(dir.toURI().toString());
      pane=new BorderPane();
      pane.setCenter(gameContainer);
      pane.setBackground(new Background(new BackgroundImage(background,null,null,null,new BackgroundSize(Constantes.MAXIMUM_WIDHT,Constantes.MAXIMUM_HEIGTH,false,false,false,true))));
      //playMusic();
      agregarOvnis();
      moverOvnis();
     pane.setBottom(lab);
  }
  
  /**
   *
   * @return
   */
  public BorderPane getRoot(){
      return pane;
  }
  
  /**
   *
   */
  public void playMusic(){
      File dir=new File(Constantes.GAME_BACKGROUND_MUSIC);
      Media music=new Media(dir.toURI().toString());
      player=new MediaPlayer(music);
      player.setOnEndOfMedia(new Runnable() {
      @Override
          public void run() {
              player.seek(Duration.ZERO);
          }
      });
      player.play();
  }
  
  public void agregarOvnis(){
      this.ovnis=new Ovni[paneOvnis.length][paneOvnis[0].length];
      for(int i=0;i&lt;paneOvnis.length;i++){
          for(int j=0;j&lt;paneOvnis[0].length;j++){    
              Pane paneOvni=new Pane();
              Ovni ovni=new OvniGris(paneOvni);
              ovni.setLocation(Constantes.POS_OVNI_X+Constantes.OVNI_SPACING_X*j,Constantes.POS_OVNI_Y+Constantes.OVNI_SPACING_Y*i);
              this.gameContainer.getChildren().add(paneOvni);
              this.paneOvnis[i][j]=paneOvni;
              this.ovnis[i][j]=ovni;
          }
      }
  }
  
  /**
   *
   * @param e
   */
  public void moverNave(Event e){
      ManejadorTeclas manager=new ManejadorTeclas();
      manager.handle((KeyEvent) e);
  }
  
  public void moverOvnis(){
      ParallelTransition animaciones=new ParallelTransition();
      for(int i=0;i&lt;ovnis.length;i++){
          for(int j=0;j&lt;ovnis[i].length;j++){
              Timeline animacionOvnis=new Timeline();
              KeyFrame kf=new KeyFrame(Duration.millis(900),new ManejadorMovimientos(i,j));
              animacionOvnis.getKeyFrames().add(kf);
              animacionOvnis.setCycleCount(Timeline.INDEFINITE);
              animacionOvnis.setAutoReverse(false);
              animaciones.getChildren().add(animacionOvnis);
          }
      }
      animaciones.play();
  }
  
  private class ManejadorTeclas implements EventHandler&lt;KeyEvent&gt;{
  
      @Override
      public void handle(KeyEvent event) {
          double movimiento=Constantes.MOVIMIENTO_NAVE;
          if(event.getCode()==KeyCode.RIGHT &amp;&amp; nave.getLocationX()+Constantes.MOVIMIENTO_NAVE&lt;Constantes.MAXIMUM_WIDHT )
              nave.setLocationX(nave.getLocationX()+3);
          else if(event.getCode()==KeyCode.LEFT &amp;&amp; nave.getLocationX()-Constantes.MOVIMIENTO_NAVE&gt;0 )
              nave.setLocationX(nave.getLocationX()-3);
          else if(event.getCode()==KeyCode.ESCAPE){ 
              pane.getScene().getWindow().hide();
          }
      }
  }
  
  private class ManejadorMovimientos implements EventHandler&lt;ActionEvent&gt;{
  
      int i;
      int j;
      int orientacion=1;
  
      public ManejadorMovimientos(int i, int j){
          this.i=i;
          this.j=j;
      }
  
      @Override
      public void handle(ActionEvent event) {
          double distanciaMaxDer=maxDistanceRight();
          double distanciaMaxIzq=maxDistanceLeft();
          lab.setText(""+distanciaMaxDer+","+ovnis[0][5].getXLocation());
          if(orientacion==1)
             if(distanciaMaxDer-30&gt;0){ 
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation()+30,ovnis[i][j].getYLocation());
             }
             else{
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);   
              orientacion=-1;                
             }
          else{
             if(distanciaMaxIzq-30&gt;30){ 
             ovnis[i][j].setLocation(ovnis[i][j].getXLocation()-30,ovnis[i][j].getYLocation());
             }
             else{
              ovnis[i][j].setLocation(ovnis[i][j].getXLocation(),ovnis[i][j].getYLocation()+20);
              orientacion=1;
             }
          }
  
      }
  
      private double maxDistanceRight(){
          int j=ovnis[0].length-1;
          while(j&gt;=0){
              for(int i=0;i&lt;ovnis.length;i++){
                  if(ovnis[i][j]!=null){
                      return 1.25*Constantes.MAXIMUM_WIDHT-ovnis[i][j].getXLocation();
                  }
              }
              j--;
          }
          return -1;
      }
  
      private double maxDistanceLeft(){
          int j=0;
          while(j&lt;ovnis[0].length){
              for(int i=0;i&lt;ovnis.length;i++){
                  if(ovnis[i][j]!=null){
                      return ovnis[i][j].getXLocation()-30;
                  }
              }
              j++;
          }
          return -1;
      }
  
  }
  </code></pre>
  
  <p>}  </p>