JavaFX Game (Connect Four)

Tags

, , ,

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.getColumnConstraints().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());
                }
            }
            
        }
    }
} 

JavaFX 2 Loading Indicator

A simple way to create a loading indicator in JavaFX 2.

Code:

 
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Parent;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.util.Duration;

public class LoadingIndicator extends Parent{
    
    private Timeline timeline = new Timeline();
    
    private DoubleProperty stroke = new SimpleDoubleProperty(100.0);
    
    
    public LoadingIndicator(){
        super();
        
        timeline.setCycleCount(Timeline.INDEFINITE);
        
        final KeyValue kv = new KeyValue(stroke, 0);
        final KeyFrame kf = new KeyFrame(Duration.millis(1500), kv);
        
        timeline.getKeyFrames().add(kf);
        timeline.play();        
        
        VBox root = new VBox(3);
        
        StackPane progressIndicator = new StackPane();
        
        Rectangle bar = new Rectangle(350,13);
        bar.setFill(Color.TRANSPARENT);
        bar.setStroke(Color.WHITE);
        bar.setArcHeight(15);
        bar.setArcWidth(15);
        bar.setStrokeWidth(2);
        
        Rectangle progress = new Rectangle(342,6);
        progress.setFill(Color.WHITE);
        progress.setStroke(Color.WHITE);
        progress.setArcHeight(8);
        progress.setArcWidth(8);
        progress.setStrokeWidth(1.5);
        progress.getStrokeDashArray().addAll(3.0,7.0,3.0,7.0);
        progress.strokeDashOffsetProperty().bind(stroke);
        
        
        progressIndicator.getChildren().add(progress);
        progressIndicator.getChildren().add(bar);
        
        root.getChildren().add(progressIndicator);
        
        Text label = new Text("Loading...");
        label.setFill(Color.WHITE);
        
        root.getChildren().add(label);
        
        getChildren().add(root);
        
    }
    
}


GWT and HTML5 Canvas Demo

This is my first experiment with GWT and HTML5 Canvas. My first attempt is to create rectangles, with just a few lines of code I came up something like this:

Sample

Code:

 

public class GwtHtml5 implements EntryPoint {
	
	static final String canvasHolderId = "canvasholder";
	static final String unsupportedBrowser = "Your browser does not support the HTML5 Canvas";
	static final int height = 400;
	static final int width = 500;
	final CssColor colorRed = CssColor.make("red");
	final CssColor colorGreen = CssColor.make("green");
	final CssColor colorBlue = CssColor.make("blue");
	Canvas canvas;
	Context2d context;
	
	
	public void onModuleLoad() {
		canvas = Canvas.createIfSupported();
		if (canvas == null) {
		      RootPanel.get(canvasHolderId).add(new Label(unsupportedBrowser));
		      return;
		}
		createCanvas();
	}
	
	private void createCanvas(){
		
	    canvas.setWidth(width + "px");
	    canvas.setHeight(height + "px");
	    canvas.setCoordinateSpaceWidth(width);
	    canvas.setCoordinateSpaceHeight(height);
	    
	    RootPanel.get(canvasHolderId).add(canvas);
	    
	    context = canvas.getContext2d();
	    
	    context.beginPath();
	    context.setFillStyle(colorRed);
	    context.fillRect(100, 50, 100, 100);
	    context.setFillStyle(colorGreen);
	    context.fillRect(200, 150, 100, 100);
	    context.setFillStyle(colorBlue);
	    context.fillRect(300, 250, 100, 100);
	    context.closePath();
	    
	}
	
}

And my Spring balls experiment with some codes that I found on the Web.

Demo

Click to view Demo

JavaFX 2 Transition

An example of a faded Path in JavaFx. It has two different canvas the one in the left side is the Fade Transition and other one in the right is also a Fade Transition but with a Stroke Transition.

FadeTransition ft = new FadeTransition(Duration.millis(5000), path);
ft.setFromValue(1.0);
ft.setToValue(0.0);
ft.play();

To change the stroke color of a shape simply use the Stroke Transition.

StrokeTransition sT = new StrokeTransition(Duration.millis(2000), path, Color.LIME, Color.YELLOW);
sT.play();


GWT Custom Button using UIBinder

Here’s an example on how to create a custom button using UIBinder on GWT.

Click to view Demo

public class GwtUIBinderButton implements EntryPoint {

	public void onModuleLoad() {
		Button button = new Button();
		button.setText("Button");
		button.addClickHandler(new ClickHandler(){
			@Override
			public void onClick(ClickEvent event) {
				Window.alert("Button clicked");
			}
		});
		RootPanel.get("container").add(button);
	}
}
public class Button extends Composite implements HasText, HasClickHandlers, ClickHandler{

	private static ButtonUiBinder uiBinder = GWT.create(ButtonUiBinder.class);

	interface ButtonUiBinder extends UiBinder<Widget, Button> {
	}

	@UiField(provided=true)
	FocusPanel pane = new FocusPanel();
	
	@UiField(provided=true)
	Label label = new Label();
	
	public Button() {
		
		pane.addClickHandler(this);
		
		initWidget(uiBinder.createAndBindUi(this));
	}

	@Override
	public HandlerRegistration addClickHandler(ClickHandler handler) {
		return addHandler(handler, ClickEvent.getType());
	}

	@Override
	public void onClick(ClickEvent event) {
		 this.fireEvent(event);
	}

	@Override
	public String getText() {
		return label.getText();
	}

	@Override
	public void setText(String text) {
		label.setText(text);
	}

}
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
	xmlns:g="urn:import:com.google.gwt.user.client.ui">
	<ui:style>
	  .button{
		  background-color: #eeeeee;
		  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #eeeeee), color-stop(100%, #cccccc));
		  background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
		  background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
		  background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
		  background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
		  background-image: linear-gradient(top, #eeeeee, #cccccc);
		  border: 1px solid #ccc;
		  border-bottom: 1px solid #bbb;
		  -webkit-border-radius: 3px;
		  -moz-border-radius: 3px;
		  -ms-border-radius: 3px;
		  -o-border-radius: 3px;
		  border-radius: 3px;
		  color: #333;
		  font: bold 11px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
		  line-height: 1;
		  padding: 0px 0;
		  text-align: center;
		  text-shadow: 0 1px 0 #eee;
		  width: 120px; 
	  }
	  .button:hover{
		  background-color: #dddddd;
		  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #dddddd), color-stop(100%, #bbbbbb));
		  background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb);
		  background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb);
		  background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
		  background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
		  background-image: linear-gradient(top, #dddddd, #bbbbbb);
		  border: 1px solid #bbb;
		  border-bottom: 1px solid #999;
		  cursor: pointer;
		  text-shadow: 0 1px 0 #ddd;
	   }
	  .button:active{
		  border: 1px solid #aaa;
		  border-bottom: 1px solid #888;
		  -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
		  -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
		  box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 
	   }
	   .pane{
		  text-align: center;
	   }
	</ui:style>
	<g:SimplePanel ui:field="pane" styleName="{style.button}">
		<g:Label ui:field="label"></g:Label>
	</g:SimplePanel>
</ui:UiBinder> 

Adding an Image:

	<g:SimplePanel ui:field="pane" styleName="{style.button}">
		<g:HTMLPanel>
			<table align="center">
				<tr>
					<td>
						<g:Image styleName="{style.pane}" url="gwt-logo-42x42.png"></g:Image>
					</td>
					<td>
						<g:Label ui:field="label"></g:Label>
					</td>
				</tr>
			</table>
		</g:HTMLPanel>
	</g:SimplePanel>

Click to view Demo

JavaFX 2 Form

This is a simple JavaFX Login Form with a TRON like effect.
In this example I am using CSS to style the TextField and Button. Here is the snippet of the CSS and Effect code:

.text-field{
   -fx-background-color: transparent;
   -fx-border-color: #00CCFF;
   -fx-text-fill: white;
}

.password-field{
   -fx-background-color: transparent;
   -fx-border-color: #00CCFF;
   -fx-text-fill: white;
}

.button{
   -fx-background-color: transparent;
   -fx-border-color: white;
   -fx-background-radius: 30;
   -fx-border-radius: 30;
   -fx-text-fill: white;
   -fx-font-weight: bold;
   -fx-font-size: 14px;
   -fx-padding: 10 20 10 20;
}

DropShadow effect = new DropShadow();
        effect.setColor(color);
        effect.setBlurType(BlurType.GAUSSIAN);
        effect.setSpread(spread);
        effect.setRadius(radius);



JavaFX 2 Custom Shapes

Sometimes using an Image will limit you in adding an effect on it, especially if you’re working on animations or a game application. So to give an example I tried creating a playing card suit shapes using the Path class and the Path elements.

Here is the code snippet of the Spade I made:

Path spade = new Path();
spade.getElements().add(new MoveTo(25.0f, 0.0f));
spade.getElements().add(new LineTo(45.0f, 30.0f));
spade.getElements().add(QuadCurveToBuilder.create()
.controlX(40.0f)
.controlY(50.0f)
.x(27.0f)
.y(30.0f)
.build());
spade.getElements().add(QuadCurveToBuilder.create()
.controlX(28.0f)
.controlY(35.0f)
.x(35.0f)
.y(50.0f)
.build());
spade.getElements().add(new LineTo(15.0f, 50.0f));
spade.getElements().add(QuadCurveToBuilder.create()
.controlX(22.0f)
.controlY(35.0f)
.x(23.0f)
.y(30.0f)
.build());
spade.getElements().add(QuadCurveToBuilder.create()
.controlX(10.0f)
.controlY(50.0f)
.x(5.0f)
.y(30.0f).build());
spade.getElements().add(new LineTo(25.0f, 0.0f));


JavaFX 2.0 Neon Globe

Tags

This is my first JavaFX 2.0 example that is developed on Mac, using the JavaFX 2.1 Developer Preview for Mac. To give an example I created a 3D spinning Neon Globe. I’d play much around with the JavaFX Transforms and Shapes to the create neon objects.

It would be good if the JavaFX team will include the other  JavaFX 1.3 variant  Shape like ShapeIntersect, ShapeSubtract and DelegateShape for the next releases of JavaFX.




JavaFX 2.0 Shape Experiment using Circle

Tags

This example is my experiment using javafx.scene.shape.Circle in JavaFX.

Figures below uses 3 circles only to create a 3D Object and to change the visual view of the circles you have to set the StrokeLineCap of the circles, the end cap styles: StrokeLineCap.BUTT, StrokeLineCap.ROUND, and StrokeLineCap.SQUARE and you need to set the StrokeDashArray aswell by adding lengths of the dash segments.

I posted a few lines of code below:


circle.setStrokeLineCap(StrokeLineCap.BUTT)
circle.getStrokeDashArray().addAll(1.0, 13.0);
circle.setStrokeWidth(215);
circle.setRadius(100);


Simple JavaFX 2.0 3D Object

Tags

A simple JavaFX 2.0 3D  example with Path Transition and Timeline Animation.



public class Main extends Application {

private static final double WIDTH = 700, HEIGHT = 500;
private PathTransition pathBackFaceTransition;
private PathTransition pathFrontFaceTransition;
private Timeline animation;

private void init(Stage primaryStage) {

Group root = new Group();
primaryStage.setTitle("JavaFX 3D");
primaryStage.setResizable(false);
Scene scene = new Scene(root, WIDTH, HEIGHT, true);
scene.setFill(Color.BLACK);
primaryStage.setScene(scene);
PerspectiveCamera camera = new PerspectiveCamera();
Translate translate = new Translate(WIDTH / 2, HEIGHT / 2);
Rotate rotate = new Rotate(180, Rotate.Y_AXIS);
primaryStage.getScene().setCamera(camera);
root.getTransforms().addAll(translate, rotate);

Node node = create3dContent();

root.getChildren().add(node);
}

public void play(){
pathBackFaceTransition.play();
pathFrontFaceTransition.play();
}

@Override
public void stop(){
pathBackFaceTransition.stop();
pathFrontFaceTransition.stop();
}

public Node create3dContent() {

final Face cube = new Face(250);

cube.rx.setAngle(0);
cube.ry.setAngle(0);
cube.rz.setAngle(0);

cube.setOnMouseMoved(new EventHandler(){
@Override
public void handle(final MouseEvent arg0) {

animation = new Timeline();

animation.getKeyFrames().addAll(
new KeyFrame(new Duration(2000),
new KeyValue(cube.rx.angleProperty(),arg0.getY()),
new KeyValue(cube.ry.angleProperty(),-arg0.getX()),
new KeyValue(cube.rz.angleProperty(),arg0.getY())
));
animation.play();
}
});

return new Group(cube);
}

public class Face extends Group {

final Rotate rx = new Rotate(0, Rotate.X_AXIS);
final Rotate ry = new Rotate(0, Rotate.Y_AXIS);
final Rotate rz = new Rotate(0, Rotate.Z_AXIS);

RectangleBuilder frontFace;// front face
RectangleBuilder rightFace;// right face
RectangleBuilder leftFace;// left face
RectangleBuilder backFace;// back face

public Face(double size) {

Color[] colors = {Color.TRANSPARENT, Color.YELLOW};

backFace = RectangleBuilder.create()
.strokeDashArray(1.0,6.0)
.width(size)
.height(size)
.fill(colors[0])
.strokeWidth(2)
.stroke(Color.BLUE)
.translateX(-0.5 * size)
.translateY(-0.5 * size)
.translateZ(-0.5*size)
.rotationAxis(Rotate.Z_AXIS)
.rotate(45);
rightFace = RectangleBuilder.create()
.strokeDashArray(1.0,6.0)
.width(size)
.height(size)
.fill(colors[0])
.strokeWidth(2)
.stroke(Color.BLUE)
.translateX(-1 * size)
.translateY(-0.5 * size)
.rotationAxis(Rotate.Y_AXIS)
.rotate(90);
leftFace = RectangleBuilder.create()
.strokeDashArray(1.0,6.0)
.width(size)
.height(size)
.fill(colors[0])
.strokeWidth(2)
.stroke(Color.BLUE)
.translateX(0)
.translateY(-0.5 * size)
.rotationAxis(Rotate.Y_AXIS)
.rotate(90);
frontFace = RectangleBuilder.create()
.strokeDashArray(1.0,6.0)
.width(size)
.height(size)
.fill(colors[0])
.strokeWidth(2)
.stroke(Color.BLUE)
.translateX(-0.5 * size)
.translateY(-0.5 * size)
.translateZ(0.5*size)
.rotationAxis(Rotate.Z_AXIS)
.rotate(225);

Rectangle rectangleFrontFace = frontFace.build();
Rectangle rectangleRightFace = rightFace.build();
Rectangle ractangleLeftFace = leftFace.build();
Rectangle rectangleBackFace = backFace.build();

Bloom backFaceBloomEffect = new Bloom();
Circle backCircle = new Circle();
backCircle.setStrokeWidth(10);
backCircle.setRadius(10);
backCircle.setStrokeLineCap(StrokeLineCap.ROUND);
backCircle.setStroke(colors[1]);
backCircle.getStrokeDashArray().addAll(1.0, 20.0);
backCircle.setTranslateX(-0.5 * size);
backCircle.setTranslateY(-0.5 * size);
backCircle.setTranslateZ(-0.5 * size);
backCircle.setEffect(backFaceBloomEffect);

Bloom frontFaceBloomEffect = new Bloom();
Circle frontCircle = new Circle();
frontCircle.setStrokeWidth(10);
frontCircle.setRadius(10);
frontCircle.setStrokeLineCap(StrokeLineCap.ROUND);
frontCircle.setStroke(colors[1]);
frontCircle.getStrokeDashArray().addAll(1.0, 20.0);
frontCircle.setTranslateX(-0.5 * size);
frontCircle.setTranslateY(-0.5 * size);
frontCircle.setTranslateZ(0.5 * size);
frontCircle.setEffect(frontFaceBloomEffect);

pathBackFaceTransition = new PathTransition();
pathBackFaceTransition.setPath(rectangleBackFace);
pathBackFaceTransition.setNode(frontCircle);
pathBackFaceTransition.setDuration(Duration.seconds(4));
pathBackFaceTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathBackFaceTransition.setCycleCount(Timeline.INDEFINITE);

pathFrontFaceTransition = new PathTransition();
pathFrontFaceTransition.setPath(rectangleFrontFace);
pathFrontFaceTransition.setNode(backCircle);
pathFrontFaceTransition.setDuration(Duration.seconds(4));
pathFrontFaceTransition.setOrientation(OrientationType.ORTHOGONAL_TO_TANGENT);
pathFrontFaceTransition.setCycleCount(Timeline.INDEFINITE);

getChildren().addAll(backCircle, frontCircle, rectangleBackFace, rectangleRightFace, ractangleLeftFace, rectangleFrontFace);
getTransforms().addAll(rz, ry, rx);

}
}

@Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
play();
}

public static void main(String[] args) {
launch(args);
}

}

Follow

Get every new post delivered to your Inbox.