Desktop Java

JavaFX Game (Connect Four)

This is my first JavaFX game tutorial and my first blog post about JavaFX panel. I made this connect four game with just 200+ lines of code just enough for a simple game. I used the GridPane panel here to lay out the disks, GridPane is one of the JavaFX layout pane but it is different from the other pane because it lays out its children within a flexible grid of rows and columns.

Here is the code snippet on how to set the GridPanes column and row constraint:

gridpane.getColumnConstraints().addAll(new ColumnConstraints(100,100,Double.MAX_VALUE), 
                new ColumnConstraints(100,100,Double.MAX_VALUE),
                new ColumnConstraints(100,100,Double.MAX_VALUE),
                new ColumnConstraints(100,100,Double.MAX_VALUE));
        gridpane.getRowConstraints().addAll(new RowConstraints(100,100,Double.MAX_VALUE), 
                new RowConstraints(100,100,Double.MAX_VALUE),
                new RowConstraints(100,100,Double.MAX_VALUE),
                new RowConstraints(100,100,Double.MAX_VALUE));

The GridPane will have 4 rows and 4 columns 100 wide square size grid.

You can have the rest of the code below enjoy.

import javafx.animation.TranslateTransition;
import javafx.application.Application;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.effect.DropShadow;
import javafx.scene.effect.Reflection;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Path;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.stage.Stage;
import javafx.util.Duration;


/**
 *
 * @author mark_anro
 */
public class Main extends Application {

    /**
     * @param args the command line arguments
     */
    
    private SimpleObjectProperty<Color> playerColorProperty = new SimpleObjectProperty<Color>(Color.RED);
    private int r;
    private int c;
    
    
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        
        final BorderPane root = new BorderPane();
        final GridPane gridpane = new GridPane();
        primaryStage.setTitle('JavaFX Connect Four');
        primaryStage.setResizable(true);
        
        final Button addCellButton = new Button('Add Grids');
        
        Scene scene = new Scene(root, 750, 680, true);
        scene.setFill(Color.BLACK);
        scene.getStylesheets().add('net/glyphsoft/styles.css');
        
        gridpane.setTranslateY(20);
        gridpane.setAlignment(Pos.CENTER);
        
        gridpane.getColumnConstraints().addAll(new ColumnConstraints(100,100,Double.MAX_VALUE), 
                new ColumnConstraints(100,100,Double.MAX_VALUE),
                new ColumnConstraints(100,100,Double.MAX_VALUE),
                new ColumnConstraints(100,100,Double.MAX_VALUE));
        gridpane.getRowConstraints().addAll(new RowConstraints(100,100,Double.MAX_VALUE), 
                new RowConstraints(100,100,Double.MAX_VALUE),
                new RowConstraints(100,100,Double.MAX_VALUE),
                new RowConstraints(100,100,Double.MAX_VALUE));
        
        createGrids(gridpane);
        
        root.setCenter(gridpane);
        
        DropShadow effect = new DropShadow();
        effect.setColor(Color.BLUE);
        addCellButton.setEffect(effect);
        
        addCellButton.setTranslateY(10);
        addCellButton.setTranslateX(10);
        
        root.setTop(addCellButton);
        
        addCellButton.setOnMouseClicked(new EventHandler<MouseEvent>(){
            @Override
            public void handle(MouseEvent arg0) {
                addGrid(gridpane);
            }
        });
 
        primaryStage.setScene(scene);
        primaryStage.setResizable(false);
        primaryStage.show();
    }
    
    //Add Column and Row
    private void addGrid(final GridPane gridpane){
        gridpane.getColumnConstraints().addAll(new ColumnConstraints(100,100,Double.MAX_VALUE));
        gridpane.getRowConstraints().addAll(new RowConstraints(100,100,Double.MAX_VALUE));
        createGrids(gridpane);
    }
    
    //Create Grids
    private void createGrids(final GridPane gridpane){
        gridpane.getChildren().clear();
        for(r=0;r<gridpane.getRowContraints().size(); r++){
            for(c=0; c<gridpane.getColumnConstraints().size(); c++){
                
            Rectangle rect = new Rectangle(100,100);
            Circle circ = new Circle(47);
            circ.centerXProperty().set(50);
            circ.centerYProperty().set(50);
            Shape cell = Path.subtract(rect, circ);
            cell.setFill(Color.BLUE);
            cell.setStroke(Color.BLUE);
            cell.setOpacity(.8);
            DropShadow effect = new DropShadow();
            effect.setSpread(.2);
            effect.setRadius(25);
            effect.setColor(Color.BLUE);
            cell.setEffect(effect);
            
            
            final Circle diskPreview = new Circle(40);
            diskPreview.setOpacity(.5);
            diskPreview.setFill(Color.TRANSPARENT);
            
            diskPreview.setOnMouseEntered(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    diskPreview.setFill(Color.WHITE);
                    if(playerColorProperty.get()==Color.RED){
                        diskPreview.setFill(Color.RED);
                    }else{
                        diskPreview.setFill(Color.YELLOW);
                    }
                }
            });
            
            diskPreview.setOnMouseExited(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    diskPreview.setFill(Color.TRANSPARENT);
                }
            });
            
            final Circle disk = new Circle(40);
            disk.fillProperty().bind(playerColorProperty);
            disk.setOpacity(.5);
            disk.setTranslateY(-(100*(r+1)));
            
            
            final TranslateTransition translateTranstion = new TranslateTransition(Duration.millis(300), disk);
            
            disk.setOnMouseEntered(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    diskPreview.setFill(Color.WHITE);
                    if(playerColorProperty.get()==Color.RED){
                        diskPreview.setFill(Color.RED);
                    }else{
                        diskPreview.setFill(Color.YELLOW);
                    }
                }
            });
            
            disk.setOnMouseExited(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    diskPreview.setFill(Color.TRANSPARENT);
                }
            });
            
            disk.setOnMouseClicked(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    if(disk.getTranslateY()!=0){
                        translateTranstion.setToY(0);
                        translateTranstion.play();
                        if(playerColorProperty.get()==Color.RED){
                            playerColorProperty.set(Color.YELLOW);
                            disk.fillProperty().bind(new SimpleObjectProperty<Color>(Color.RED));
                        }else{
                            playerColorProperty.set(Color.RED);
                            disk.fillProperty().bind(new SimpleObjectProperty<Color>(Color.YELLOW));
                        }
                    }
                }
            });
            
            diskPreview.setOnMouseClicked(new EventHandler<MouseEvent>(){
                @Override
                public void handle(MouseEvent arg0) {
                    if(disk.getTranslateY()!=0){
                        translateTranstion.setToY(0);
                        translateTranstion.play();
                        if(playerColorProperty.get()==Color.RED){
                            playerColorProperty.set(Color.YELLOW);
                            disk.fillProperty().bind(new SimpleObjectProperty<Color>(Color.RED));
                        }else{
                            playerColorProperty.set(Color.RED);
                            disk.fillProperty().bind(new SimpleObjectProperty<Color>(Color.YELLOW));
                        }
                    }
                }
            });
            
            
            StackPane stack = new StackPane();
            
            stack.getChildren().addAll(cell, diskPreview, disk);
            
            gridpane.add(stack, c, r); 
            
                if(r==gridpane.getColumnConstraints().size()-1){
                    stack.setEffect(new Reflection());
                }
            }
            
        }
    }
} 

Happy coding and don’t forget to share!

Reference: JavaFX Game (Connect Four) from our JCG partner Mark Anro Silva at the GlyphSoft blog.

Mark Anro Silva

Software Engineer | UI/UX Engineer, Java, JavaFX, GWT and Scala.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Calogero
Calogero
6 years ago

Hello ! Thanks for this tutorial.
Please : can we have the stylesheet int this directory “net/glyphsoft/styles.css”, not accessible for us ? This will be very kind of you !

Lawrence
Lawrence
2 years ago

Nice tutorial, very easy to follow.

There’s a small typo in the example (line 101)
when iterating the rows (r) getColumnConstraints() should be replaced with getRowContraints()

Last edited 2 years ago by Lawrence
Back to top button