平行过渡的运动问题´;JavaFX8中的s事件处理程序

平行过渡的运动问题´;JavaFX8中的s事件处理程序,java,javafx,javafx-8,Java,Javafx,Javafx 8,我正在用javafx做一个大学项目:一个类似于太空入侵者的游戏。我试图用一个平行过渡制作每个ovni的动画,创建一个时间线动画,并将其添加到每个ovni的平行过渡中,为它们中的每一个管理EventHandler,以便将ovni移动到X位置,并在窗口左边界时移动到Y位置。问题是,当我播放动画时,只有第一行在X位置正确移动,但其他行没有。换句话说,当其他行在x位置移动一定距离时,它们不会在rigth边界上完成运动,而是在Y位置移动。结果如下: 这是构建OVNI的方法: public Shape bu

我正在用javafx做一个大学项目:一个类似于太空入侵者的游戏。我试图用一个平行过渡制作每个ovni的动画,创建一个时间线动画,并将其添加到每个ovni的平行过渡中,为它们中的每一个管理EventHandler,以便将ovni移动到X位置,并在窗口左边界时移动到Y位置。问题是,当我播放动画时,只有第一行在X位置正确移动,但其他行没有。换句话说,当其他行在x位置移动一定距离时,它们不会在rigth边界上完成运动,而是在Y位置移动。结果如下:

这是构建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;
}
其次,我为ovni声明了两个矩阵:一个用于包含每个ovni形状的窗格;以及其他将包含ovni对象的

  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);
}
填充每个矩阵的方法:

public void agregarOvnis(){
    this.ovnis=new Ovni[paneOvnis.length][paneOvnis[0].length];
    for(int i=0;i<paneOvnis.length;i++){
        for(int j=0;j<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;
        }
    }
}
}

OVNI等级

    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
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;
}
}

游戏课

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<paneOvnis.length;i++){
        for(int j=0;j<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<ovnis.length;i++){
        for(int j=0;j<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<KeyEvent>{

    @Override
    public void handle(KeyEvent event) {
        double movimiento=Constantes.MOVIMIENTO_NAVE;
        if(event.getCode()==KeyCode.RIGHT && nave.getLocationX()+Constantes.MOVIMIENTO_NAVE<Constantes.MAXIMUM_WIDHT )
            nave.setLocationX(nave.getLocationX()+3);
        else if(event.getCode()==KeyCode.LEFT && nave.getLocationX()-Constantes.MOVIMIENTO_NAVE>0 )
            nave.setLocationX(nave.getLocationX()-3);
        else if(event.getCode()==KeyCode.ESCAPE){ 
            pane.getScene().getWindow().hide();
        }
    }
}

private class ManejadorMovimientos implements EventHandler<ActionEvent>{

    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>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>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>=0){
            for(int i=0;i<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<ovnis[0].length){
            for(int i=0;i<ovnis.length;i++){
                if(ovnis[i][j]!=null){
                    return ovnis[i][j].getXLocation()-30;
                }
            }
            j++;
        }
        return -1;
    }

}
公共类Juego{
专用边框窗格;
专用集装箱;
私有文件目录;
私有图像背景;
私人媒体播放器;
私人中堂;
专用窗格[][]窗格VNIS;
私人Ovni[]ovnis;
私有最终平行过渡过渡过渡期;
标签实验室;
/**
*
*/
公共Juego(){
lab=新标签();
transicionEnY=新的并行转换();
dir=新文件(constants.GAME_背景);
窗格导航窗格=新窗格();
paneOvnis=新窗格[3][6];
中堂=新中堂(中堂平面);
gameContainer=新窗格();
gameContainer.getChildren().addAll(navePane);
背景=新图像(dir.toURI().toString());
窗格=新边框窗格();
窗格。设置中心(游戏容器);
窗格.背景(新背景(新背景图像(背景,空,空,空,新背景大小(常数.最大宽度,常数.最大高度,假,假,真)));
//播放音乐();
agregarOvnis();
moverOvnis();
窗格玻璃(实验室);
}
/**
*
*@返回
*/
公共边框窗格getRoot(){
返回窗格;
}
/**
*
*/
公共音乐{
File dir=新文件(constants.GAME\u BACKGROUND\u MUSIC);
媒体音乐=新媒体(dir.toURI().toString());
播放器=新媒体播放器(音乐);
player.setOnEndOfMedia(新的Runnable(){
@凌驾
公开募捐{
player.seek(持续时间为0);
}
});
player.play();
}
公共无效agregarOvnis(){
this.ovnis=new-Ovni[paneOvnis.length][paneOvnis[0].length];

对于(int i=0;i您逐行更新位置并重新计算最右边的位置。按顺序将<代码>时间线< /代码> s添加到<代码>并行转换< /代码>中,在右下角更新之前,右上角OVI被更新,这意味着那些OUVIS将考虑要到达的最右边的位置。导致问题的最顶行ouvis前的“帧”

附加说明:

在这种情况下,使用
并行转换
是不必要的/低效的,因为单个
时间线
可以处理所有的
关键帧
s。此外,甚至多个
关键帧
s都是不必要的,因为ouvis都是在同一时间更新的,甚至一些值也应该重用

以下示例围绕更简单的对象移动:

private Rectangle[][] rects = new Rectangle[3][3];

private void moveDown() {
    for (Rectangle[] column : rects) {
        for (Rectangle r : column) {
            if (r != null) {
                r.setY(r.getY() + 5);
            }
        }
    }
}

@Override
public void start(Stage primaryStage) {
    Pane root = new Pane();
    for (int j = 0; j < rects.length; j++) {
        Rectangle[] column = rects[j];
        for (int i = 0; i < column.length; i++) {
            Rectangle rect = new Rectangle(20, 20);
            rect.setX(j * 25);
            rect.setY(i * 25);
            root.getChildren().add(rect);
            column[i] = rect;
        }
    }
    Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {

        boolean movingRight = true;

        @Override
        public void handle(ActionEvent event) {
            double maxX = Double.NEGATIVE_INFINITY;
            double minX = Double.POSITIVE_INFINITY;
            outer:
            for (int i = rects.length - 1; i >= 0; i--) {
                for (Rectangle r : rects[i]) {
                    if (r != null) {
                        maxX = r.getX() + r.getWidth();
                        break outer;
                    }
                }
            }
            outer:
            for (Rectangle[] col : rects) {
                for (Rectangle r : col) {
                    if (r != null) {
                        minX = r.getX();
                        break outer;
                    }
                }
            }
            if (movingRight) {
                if (maxX + 5 > 150) {
                    moveDown();
                    movingRight = false;
                    return;
                }
            } else {
                if (minX - 5 < 0) {
                    moveDown();
                    movingRight = true;
                    return;
                }
            }
            double dx = movingRight ? 5 : -5;
            for (Rectangle[] column : rects) {
                for (Rectangle r : column) {
                    if (r != null) {
                        r.setX(r.getX() + dx);
                    }
                }
            }
        }

    }));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

    Scene scene = new Scene(root, 150, 600);

    primaryStage.setScene(scene);
    primaryStage.show();
}
private Rectangle[]rects=新矩形[3][3];
私有无效向下移动(){
对于(矩形[]列:矩形){
用于(矩形r:列){
如果(r!=null){
r、 setY(r.getY()+5);
}
}
}
}
@凌驾
公共无效开始(阶段primaryStage){
窗格根=新窗格();
对于(int j=0;j=0;i--){
for(矩形r:rects[i]){
如果(r!=null){
maxX=r.getX()+r.getWidth();
打破外部;
}
}
}
外部:
用于(矩形[]列:矩形){
for(矩形r:col){
如果(r!=null){
minX=r.getX();
打破外部;
}
}
}
如果(向右移动){
如果(最大值+5>150){
向下移动();
movingRight=错误;
返回;
}
}否则{
如果(最小值-5<0){
向下移动();
movingRight=正确;
返回;
}
}
双dx=向右移动?5:-5;
对于(矩形[]列:矩形){
用于(矩形r:列){
如果(r!=null){
r、 setX(r.getX()+dx);
}
}
}
}
}));
timeline.setCycleCount(Animation.unfinite);
timeline.play();
场景=新场景(根,150600);
初级阶段。场景(场景);
primaryStage.show();
}

结果是这样的:请阅读如何创建感谢,非常感谢您对我的帮助!!!!!这个示例对我的项目非常有用。
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<paneOvnis.length;i++){
        for(int j=0;j<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<ovnis.length;i++){
        for(int j=0;j<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<KeyEvent>{

    @Override
    public void handle(KeyEvent event) {
        double movimiento=Constantes.MOVIMIENTO_NAVE;
        if(event.getCode()==KeyCode.RIGHT && nave.getLocationX()+Constantes.MOVIMIENTO_NAVE<Constantes.MAXIMUM_WIDHT )
            nave.setLocationX(nave.getLocationX()+3);
        else if(event.getCode()==KeyCode.LEFT && nave.getLocationX()-Constantes.MOVIMIENTO_NAVE>0 )
            nave.setLocationX(nave.getLocationX()-3);
        else if(event.getCode()==KeyCode.ESCAPE){ 
            pane.getScene().getWindow().hide();
        }
    }
}

private class ManejadorMovimientos implements EventHandler<ActionEvent>{

    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>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>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>=0){
            for(int i=0;i<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<ovnis[0].length){
            for(int i=0;i<ovnis.length;i++){
                if(ovnis[i][j]!=null){
                    return ovnis[i][j].getXLocation()-30;
                }
            }
            j++;
        }
        return -1;
    }

}
private Rectangle[][] rects = new Rectangle[3][3];

private void moveDown() {
    for (Rectangle[] column : rects) {
        for (Rectangle r : column) {
            if (r != null) {
                r.setY(r.getY() + 5);
            }
        }
    }
}

@Override
public void start(Stage primaryStage) {
    Pane root = new Pane();
    for (int j = 0; j < rects.length; j++) {
        Rectangle[] column = rects[j];
        for (int i = 0; i < column.length; i++) {
            Rectangle rect = new Rectangle(20, 20);
            rect.setX(j * 25);
            rect.setY(i * 25);
            root.getChildren().add(rect);
            column[i] = rect;
        }
    }
    Timeline timeline = new Timeline(new KeyFrame(Duration.millis(500), new EventHandler<ActionEvent>() {

        boolean movingRight = true;

        @Override
        public void handle(ActionEvent event) {
            double maxX = Double.NEGATIVE_INFINITY;
            double minX = Double.POSITIVE_INFINITY;
            outer:
            for (int i = rects.length - 1; i >= 0; i--) {
                for (Rectangle r : rects[i]) {
                    if (r != null) {
                        maxX = r.getX() + r.getWidth();
                        break outer;
                    }
                }
            }
            outer:
            for (Rectangle[] col : rects) {
                for (Rectangle r : col) {
                    if (r != null) {
                        minX = r.getX();
                        break outer;
                    }
                }
            }
            if (movingRight) {
                if (maxX + 5 > 150) {
                    moveDown();
                    movingRight = false;
                    return;
                }
            } else {
                if (minX - 5 < 0) {
                    moveDown();
                    movingRight = true;
                    return;
                }
            }
            double dx = movingRight ? 5 : -5;
            for (Rectangle[] column : rects) {
                for (Rectangle r : column) {
                    if (r != null) {
                        r.setX(r.getX() + dx);
                    }
                }
            }
        }

    }));
    timeline.setCycleCount(Animation.INDEFINITE);
    timeline.play();

    Scene scene = new Scene(root, 150, 600);

    primaryStage.setScene(scene);
    primaryStage.show();
}