Sunday, July 26, 2009

JavaFX - Peg Game.

JavaFX is a technology from SUN ( recently taken over by Oracle ) that competes against Adobe Flash and Microsoft Silverlight.

This article shows how to build a simple JavaFX program to play the 'Peg Game'.

The Peg game is played with a triangular piece of board with 15 holes in it. One hole (usually the top) is left open and golf tees are placed into the other 14. The objective is to hop over the pegs, removing the hopped peg, and in doing so remove all but one peg from the game.

Here it is in action: http://turnbasedgames.appspot.com/lastblock/Last_Block_Standing.html



To create this game I have four files:

Main.fx
TriangleBase.fx
GameSquare.fx
Util.java

Main.fx consists of:

package javafxapplication1;

import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafxapplication1.TriangleBase;


/**
* @author Lars Vogel
*/
Stage {
var rect: Rectangle;
var circ: Circle;
title: "Last Block Standing"
scene: Scene {
width: 500
height: 500
var myString = "Last Block Standing"
var gameInstance: TriangleBase = new TriangleBase;
content: [
gameInstance,
Rectangle {
x: 50,
y: 300
width: 50,
height: 15
arcHeight: 2
arcWidth: 2
stroke: Color.BLACK
strokeWidth: 2
fill: LinearGradient {
startX: 0.0
startY: 0.0
endX: 0.0
endY: 1.0
stops: [
Stop {
color: Color.ORANGE
offset: 0.0
},
Stop {
color: Color.DARKRED
offset: 0.3
},
Stop {
color: Color.ORANGE
offset: 1.0
},
]
}
onMouseClicked: function(me) {
gameInstance.restart();
}
}
Text {
fill: Color.WHITE
font: Font {
name: "Arial Bold"
size: 12
}
x: 55,
y: 315
content: "Restart"
}
]
}
}

Triangle Base:
/*
* TriangleBase.fx
*
* Created on Jul 23, 2009, 10:55:02 PM
*/

package javafxapplication1;

import javafx.scene.control.Control;
import javafx.scene.Group;
import javafx.scene.Node;

/**
* @author avalanche
*/

public class TriangleBase extends Control {
public override function create(): Node {
return group;
}

var group: Group =
Group {
content: [
]
};
public function buildContent() {
insert GameSquare{ SquareId:1 x1:50 y1:0 hasTee:false} into group.content;
insert GameSquare{ SquareId:2 x1:40 y1:20} into group.content;
insert GameSquare{ SquareId:3 x1:60 y1:20} into group.content;
insert GameSquare{ SquareId:4 x1:30 y1:40} into group.content;
insert GameSquare{ SquareId:5 x1:50 y1:40} into group.content;
insert GameSquare{ SquareId:6 x1:70 y1:40} into group.content;
insert GameSquare{ SquareId:7 x1:20 y1:60} into group.content;
insert GameSquare{ SquareId:8 x1:40 y1:60} into group.content;
insert GameSquare{ SquareId:9 x1:60 y1:60} into group.content;
insert GameSquare{ SquareId:10 x1:80 y1:60} into group.content;
insert GameSquare{ SquareId:11 x1:10 y1:80} into group.content;
insert GameSquare{ SquareId:12 x1:30 y1:80} into group.content;
insert GameSquare{ SquareId:13 x1:50 y1:80} into group.content;
insert GameSquare{ SquareId:14 x1:70 y1:80} into group.content;
insert GameSquare{ SquareId:15 x1:90 y1:80} into group.content;
}

public function restart() {
delete group.content;
buildContent();
println("performing restart");
}
postinit{
buildContent();
}

}

GameSquare:
/*
* Node.fx
*
* Created on Jul 23, 2009, 11:12:07 PM
*/

package javafxapplication1;

import javafx.scene.control.Control;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafxapplication1.Util;
import java.util.HashMap;

var clickedSquare: GameSquare= null;
var gameSquareMap = new HashMap();

public class GameSquare extends Control {
public var SquareId: Integer;
public var squareColor: Color = Color.GREEN;
public var x1: Number;
public var y1: Number;
public var hasTee: Boolean = true;

var rect: Rectangle =
Rectangle{

fill: bind squareColor;

height: (20 * 2)
width: (20 * 2 )
translateX: (x1 * 2 )
translateY: (y1 * 2)
stroke: Color.BLACK;
onMouseClicked: function(me){


// first click, and I have a tee
if (clickedSquare == null and this.hasTee == true) {
println("setting clickedsquare");
clickedSquare = this;
clickedSquare.setIsClicked(true)


// second click, and I don't have a tee
}else if(this.hasTee == false and clickedSquare != null) {
// Find square we jumped over.
var hoppedNode = Util.getHoppedNode(clickedSquare.SquareId, this.SquareId);
if (hoppedNode != -1 ) {
var hoppedSquare = gameSquareMap.get(hoppedNode) as GameSquare;
if (hoppedSquare.hasTee) {
// hopped square is now empty
hoppedSquare.setHasTee(false);
this.setHasTee(true);
clickedSquare.setHasTee(false);
}
}
clickedSquare.setIsClicked(false);
clickedSquare = null;
} else {
//invalid remove marker for first click so user can try again.
clickedSquare.setIsClicked(false);
clickedSquare = null;
}

}
}


public override function create(): Rectangle {
return rect;
}
function setIsClicked(arg:Boolean) {
if (arg==true) {
squareColor = Color.BROWN;
}
else {
setHasTee(hasTee); //set to proper color;
}
}

function setHasTee(arg:Boolean) {
hasTee = arg;
if (hasTee == true) {
squareColor = Color.GREEN;
} else {
squareColor = Color.RED;
}
}

postinit {
this.setHasTee(hasTee);
gameSquareMap.put(SquareId, this);
}
}

Util.java

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/

package javafxapplication1;

import java.util.HashMap;
import java.util.Map;

/**
*
* @author avalanche
*/
public class Util {
static Map connections = new HashMap();
static {
connections.put("1,4", 2);
connections.put("1,6",3);
connections.put("2,7",4);
connections.put("2,9",5);
connections.put("3,8",5);
connections.put("3,10",6);
connections.put("4,6",5);
connections.put("4,11",7);
connections.put("4,13",8);
connections.put("5,12",8);
connections.put("5,14",9);
connections.put("6,13",9);
connections.put("6,15",10);
connections.put("7,9",8);
connections.put("8,10",9);
connections.put("11,13",12);
connections.put("12,14",13);
connections.put("13,15",14);
}
static public int getHoppedNode(int x, int y ) {
int lowest = Math.min(x,y);
int highest = Math.max(x,y);
Integer value = connections.get(lowest+","+highest);
if ( value == null )
return -1;
else
return value;

}

}


(This article is a placeholder, I'm going to come back and comment later)