Search code examples
javaanimationjavafxtransitiongridpane

JavaFX transition animation fail to place the children of gridpane at the right place


I am writing a game similar to Bejeweled, and after running the application for some time the blocks fail to be exactly at the right place visually but logically they are at the right place. The situation is as the picture below.

enter image description here

I don't know the cause of the bug.

here are the codes for the method erase and descend. Logically these methods do well.

public void erase()
{
    for (int i = 0; i < BlockManager.length; i++)
    {
        Block block = BlockManager.blocks[BlockManager.erased[i][0]][BlockManager.erased[i][1]];
        BlockManager.blocks[BlockManager.erased[i][0]][BlockManager.erased[i][1]] = null;

        FadeTransition transition = new FadeTransition(Duration.seconds(1), block);
        transition.setFromValue(1);
        transition.setToValue(0);

        transition.setOnFinished(e ->
        {

            blockGridPan.getChildren().remove(block);

            descend();

            BlockManager.resetArrays();

        });

        transition.play();

    }

}

int[][] descend = new int[HEIGHT * WIDE][2];
int descendLength = 0;


public void descend()
{
    int[] columnX = new int[10];
    int[] theUpperOne = new int[10];

    Arrays.fill(theUpperOne, 10);
    Arrays.fill(columnX, 0);

    for (int j = 0; j < BlockManager.length; j++)
    {
        columnX[BlockManager.erased[j][0]]++;
        if (BlockManager.erased[j][1] < theUpperOne[BlockManager.erased[j][0]])
        {
            theUpperOne[BlockManager.erased[j][0]] = BlockManager.erased[j][1];
        }
    }

    TranslateTransition transition = null;

    for (int i = 0; i < 10; i++)
    { 
        if (columnX[i] == 0)
            continue;

        for (int j = WIDE - 1; j >= 0; j--)
        {
            if (BlockManager.blocks[i][j] == null)
                continue;
            int dY = 0;
            for (int k = j + 1; k < WIDE; k++)
            {
                if (BlockManager.blocks[i][k] == null)
                    dY++;
            }
            if (dY != 0)
            {
                int deltaY = dY * 60;

                transition = new TranslateTransition(Duration.seconds(1), BlockManager.blocks[i][j]);
                transition.setByY(deltaY);

                BlockManager.blocks[i][j + dY] = BlockManager.blocks[i][j];
                BlockManager.blocks[i][j + dY].setPosition(i, j + dY);
                BlockManager.blocks[i][j] = null;

                BlockManager.blocks[i][j + dY].setDescended(true);
                transition.play();
            }
        }


        for (int j = columnX[i] - 1; j >= 0; j--)
        {

            int deltYJ = j * 60;
            createOneBlock(i, j);
            BlockManager.setBlockColorWithoutCheck(BlockManager.blocks[i][j]);
            blockGridPane.add(BlockManager.blocks[i][j], i, 0);
            System.out.println("show it");

            BlockManager.blocks[i][j].setDescended(true);

            transition = new TranslateTransition(Duration.seconds(1), BlockManager.blocks[i][j]);
            transition.setByY(deltYJ);
            transition.play();

        }

    }

    if (transition != null)
        transition.setOnFinished(e ->
        {

            BlockManager.resetArrays();
            if (BlockManager.check())
                erase();

        });

}

}


Solution

  • You didn't paste your codes for your layout, so I'm going to make a guess.

    There is a potential problem when you do translate and your layout depends on boundsInParent. This is an abstract from the JavaDoc:

    The rectangular bounds of this Node which include its transforms. boundsInParent is calculated by taking the local bounds (defined by boundsInLocal) and applying the transform created by setting the following additional variables

    1. transforms ObservableList
    2. scaleX, scaleY
    3. rotate
    4. layoutX, layoutY
    5. translateX, translateY

    When your TranslateTransition animates, it is changing the block's translateY value, and if your layout is called at this time, this translate value is going to affect how the block's is going to be positioned. If your layout is managed by some kind of layout manager (i.e. pane), you need to check how they position their children.