Adding borders to GridPane JavaFX

Don't use setGridLinesVisible(true): the documentation explicitly states this is for debug only.

Instead, place a pane in all the grid cells (even the empty ones), and style the pane so you see the borders. (This gives you the opportunity to control the borders very carefully, so you can avoid double borders, etc.) Then add the content to each pane. You can also register the mouse listeners with the pane, which means you don't have to do the ugly math to figure out which cell was clicked.

The recommended way to apply a border to any region is to use CSS and a "nested background" approach. In this approach, you draw two (or more) background fills on the region, with different insets, giving the appearance of a border. So for example:

-fx-background-fill: black, white ;
-fx-background-insets: 0, 1 ;

will first draw a black background with no insets, and then over that will draw a white background with insets of 1 pixel on all sides, giving the appearance of a black border of width 1 pixel. While this may seem counter-intuitive, the performance of this is (allegedly) better than specifying border directly. You can also specify a sequence of four values for the insets for each fill, which are interpreted as the insets on the top, right, bottom, and left, respectively. So

-fx-background-fill: black, white ;
-fx-background-insets: 0, 0 1 1 0 ;

has the effect of a black border on the right and bottom, etc.

I'm also not sure SubScene is what you really want, unless you are intending attaching different cameras to each cell. If you really need a subscene, make the fill transparent to avoid drawing over the edges of the cell. You could just add the Group directly to each cell (you could probably just add the circle, depending on exactly what you need...).

Something like:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.RowConstraints;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class Game2 extends Application{
    @Override
    public void start(final Stage stage) throws Exception {
        int rows = 5;
        int columns = 5;

        stage.setTitle("Enjoy your game");

        GridPane grid = new GridPane();
        grid.getStyleClass().add("game-grid");

        for(int i = 0; i < columns; i++) {
            ColumnConstraints column = new ColumnConstraints(40);
            grid.getColumnConstraints().add(column);
        }

        for(int i = 0; i < rows; i++) {
            RowConstraints row = new RowConstraints(40);
            grid.getRowConstraints().add(row);
        }

        for (int i = 0; i < columns; i++) {
            for (int j = 0; j < rows; j++) {
                Pane pane = new Pane();
                pane.setOnMouseReleased(e -> {
                    pane.getChildren().add(Anims.getAtoms(1));
                });
                pane.getStyleClass().add("game-grid-cell");
                if (i == 0) {
                    pane.getStyleClass().add("first-column");
                }
                if (j == 0) {
                    pane.getStyleClass().add("first-row");
                }
                grid.add(pane, i, j);
            }
        }


        Scene scene = new Scene(grid, (columns * 40) + 100, (rows * 40) + 100, Color.WHITE);
        scene.getStylesheets().add("game.css");
        stage.setScene(scene);
        stage.show();
    }

    public static class Anims {

        public static Node getAtoms(final int number) {
            Circle circle = new Circle(20, 20f, 7);
            circle.setFill(Color.RED);
            Group group = new Group();
            group.getChildren().add(circle);
//            SubScene scene = new SubScene(group, 40, 40);
//            scene.setFill(Color.TRANSPARENT);
            return group;
        }
    }

    public static void main(final String[] arguments) {
        Application.launch(arguments);
    }
}

and the css:

.game-grid {
    -fx-background-color: white ;
    -fx-padding: 10 ;
}
.game-grid-cell {
    -fx-background-color: black, white ;
    -fx-background-insets: 0, 0 1 1 0 ;
}
.game-grid-cell.first-row {
    -fx-background-insets: 0, 1 1 1 0 ;
}
.game-grid-cell.first-column {
    -fx-background-insets: 0, 0 1 1 1 ;
}
.game-grid-cell.first-row.first-column {
    -fx-background-insets: 0, 1 ;
}

Simply add an H and V gap of one pixel width and let the grid pane's background color "shine" through:

.my-grid-pane {
    -fx-background-color: lightgray;
    -fx-vgap: 1;
    -fx-hgap: 1;
    -fx-padding: 1;
}

If the grid pane's background color spreads from outside more than one pixel (will happen if its parent is larger than itself), just wrap the grid in a Group!