Processingjs — Java syntax without the browser plugin

While super impressed with the processing language, I am also very excited that processingjs has ported processing to the HTML canvas object thus eliminating the Java applet/plugin requirement. And if that is not enough…the processingjs syntax looks just like that of Java (calling all Java developers)!

So as my first simple example of processingjs, I have created a Sine wave generator.
Many thanks to both processing/js teams.

* Please use the Firefox or Google Chrome browser if you are unable to view the above graphic

 
// Global variables
int radius = 60.0;
int X, Y;
int count = 0;
ArrayList points;
 
 
class Point {
  float x, y; // X-coordinate, y-coordinate
  // Constructor
  Point(int xpos, int ypos) {
    x = xpos;
    y = ypos;
  }
}
 
// Setup the Processing Canvas
void setup(){
  size( 500, 203 );
  strokeWeight( 2 );
  frameRate( 45 );
  X = 35;
  Y = 97;
  points = new ArrayList();
  points.add(new Point(X,Y));
 
}
 
// Main draw loop
void draw(){
  var xfac=X+radius/2*cos(frameCount*PI/180);
  var yfac=Y+radius/2*sin(frameCount*PI/180);
  background(255,255,255);
 
  // Set fill-color 
  fill( count, yfac, yfac );
  stroke(40);
 
  if(count<359){
      count++;
  }else{
     count = 0;
     points = new ArrayList();
  }
 
  //main circle
  ellipse( X, Y, radius, radius );
  //perimeter circle
  ellipse( xfac ,yfac, 5, 5 );
  //draw point
   points.add(new Point(100+count,yfac));
   //drawing line
  line(xfac ,yfac,100+count,yfac);
  //line from center to perimeter of circle
  line(X ,Y,xfac ,yfac);
  //graph lines
  stroke(200);
  line(X+65 ,Y,460,Y);
  line(X+65 ,Y+30,460,Y+30);
  line(X+65 ,Y-30,460,Y-30);
 
  //sin wave
  stroke(40);
 
  for (int i = points.size()-1; i >= 0; i--) {
     Point ball = (Point) points.get(i);
     point(ball.x,ball.y);
   }
 
}

JavaFX, National Public Radio NPR and Google Maps api Mashup

JavaFX + webservice api = Mashup Win!

Below is a simple mashup with the Nation Public Radio NPR api and Google Maps api.

Within 125 lines of code and a few really good webservice api’s , JavaFX can parse and display any mashup quite easily.

The mashup below takes a user zip code and finds and displays all NPR radio stations within that query zip code.

Many thanks to Google Maps for their api service, and  the NPR webservice api (lots of good stuff here).

Also thanks to this post regarding JavaFX and Google Maps.

NPR Google Map Mashup

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.control.TextBox;
import javafx.scene.control.Label;
import javafx.scene.control.Button;
import javafx.data.pull.Event;
import javafx.data.pull.PullParser;
import javafx.io.http.HttpRequest;
import javafx.io.http.URLConverter;
import javafx.ext.swing.SwingLabel;
 
var base_url:String ="http://maps.google.com/staticmap?zoom=7&amp;size=600x500";
var s:String ="http://maps.google.com/staticmap?markers=38,-77&amp;zoom=7&amp;size=600x500";
var stations:String="Stations:";
 
bound function getMapImage(s):Image {
var mapurl:String = "{s}";
var map:Image = Image {
  url: mapurl;
}
return map;
}
 
function parseNprQuery(zip:String):Void {
def getRequest: HttpRequest = HttpRequest {
  var zip_enc = URLConverter{}.encodeString(zip);
  var name ="";
  location: "http://api.npr.org/stations.php?apiKey=YOUR_API_KEY&amp;zip={zip_enc}";
  onInput: function(is: java.io.InputStream) {
    def parser = PullParser {
      documentType: PullParser.XML;
      input: is;
      onEvent: function(event: Event) {
        if (event.type == PullParser.END_ELEMENT) {
          if (event.qname.name == "marketCity") {
            getLatLng(event.text);
          }else if (event.qname.name == "name") {
            name = event.text;
          }else if (event.qname.name == "frequency") {
            stations="{stations} {name} {event.text}";
          }
        }
      }
    }
    parser.parse();
    parser.input.close();
  }
}
getRequest.start();
}
 
function getLatLng(place:String):Void {
def getRequest: HttpRequest = HttpRequest {
  var place_enc = URLConverter{}.encodeString(place);
  location: "http://maps.google.com/maps/geo?q={place_enc}&amp;output=xml";
  onInput: function(is: java.io.InputStream) {
    def parser = PullParser {
      documentType: PullParser.XML;
      input: is;
      onEvent: function(event: Event) {
        if (event.type == PullParser.END_ELEMENT) {
          if (event.qname.name == "code" and event.text == "602") {
            //TODO:alert user of problem
          }
          else if (event.qname.name == "coordinates") {
            var pts = event.text.split(",");
            s="{s}&amp;markers={java.lang.Float.parseFloat(pts[1])},{java.lang.Float.parseFloat(pts[0])}";
          }
        }
      }
    }
    parser.parse();
    parser.input.close();
  }
}
getRequest.start();
}
 
var mapview:ImageView = ImageView {
layoutX:10 layoutY:75;
image: bind getMapImage(s);
}
 
def zipLabel = SwingLabel {
  layoutX:10 layoutY:15;
  text: "Enter US Zip code :"
}
 
def zip = TextBox {
  layoutX:120 layoutY:10;
  text: ""
  columns: 10
  selectOnFocus: true
}
 
def btnUpdateMap = Button {
layoutX:240 layoutY:10;
text: "Get NPR Radio Stations"
action: function() {
  var addr:String = zip.text;
  s=base_url;
  stations="Stations :";
  parseNprQuery(addr);
}
}
 
def stationsLabel = Label {
layoutX:10 layoutY:45;
width:650;
text: bind stations;
}
 
def stage = Stage {
title : "JavaFX NPR Google Maps"
scene: Scene {
  width: 650
  height: 600
  content: [zipLabel, zip,btnUpdateMap,stationsLabel,mapview]
    }
}

JavaFX Bubble Breaker

BubbleBreaker

webstart

Originally posted by me on ericonjavafx.com

package bubblebreaker;
 
import javafx.stage.Stage;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
 
import java.util.Random;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.CustomNode;
import javafx.scene.effect.Glow;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.scene.text.TextAlignment;
import javafx.scene.effect.InnerShadow;
import javafx.scene.effect.DropShadow;
import javafx.ext.swing.SwingButton;
 
var shift = 10; // from from scene.x and scene.y
var score_count: Number = 0;
var group: Group = new Group;
var slots = [];
var checkedGroup = Group {
        };
var totalScore = 0;
 
function initGroup() {
    group = new Group;
    slots = [];
    totalScore = 0;
 
    for (i in [1..10]) {
        for (j in [1..10]) {
            insert "true" into slots;
            insert Ball2 {
                radius: 25;
                vx: i * 50 + shift;
                vy: j * 50 + (shift * 5);
                slot: sizeof slots;
                id: "{sizeof slots}";
            } into group.content;
        }
    }
    insert "true" into slots;//this is required for the 100 slot
 
}
 
initGroup();
 
function fallStep() {
    var aball ;
    //1. iterate through the entire set of balls
    for (node in group.content) {
        aball = (node as Ball2);
        //2. if a ball is marked for deletion then remove from the group and mark the slot as empty(false)
        if (aball.flaggedfordeletion) {
            slots[aball.slot] = "false";
            totalScore = totalScore + Integer.parseInt(aball.score);
            delete aball from group.content;
        }
        //3. if the slot below a ball is empty and not ending with a 1
        if (slots[aball.slot + 1] == "false") {
            var aa = aball.slot + 1;
            if (aa == 11 or aa == 21 or aa == 31 or aa == 41 or aa == 51 or aa == 61 or aa == 71 or aa == 81 or aa == 91) {
                //do nothing
 
            } else {
                //4. mark the slot at taken(true) and move the ball into it....also mark the previous slot as empty(false);
                slots[aball.slot + 1] = "true";
                slots[aball.slot] = "false";
                aball.slot = aball.slot + 1;
                aball.vy = aball.vy + 50;
                aball.id = "{aball.slot}";
            }
        }
 
    }
}
 
function shiftRightStep() {
    for (i in [100..20 step -10]) {
        if (slots[i] == "false") {
            for (j in [(i - 10)..1 step -1]) {
                var aa =
                        group.lookup("{j}") as Ball2;
                if (aa != null) {
                    slots[j + 10] = "true";
                    aa.slot = aa.slot + 10;
                    aa.vx = aa.vx + 50;
                    aa.id = "{aa.slot}";
                    slots[j] = "false";
                }
            }
        }
    }
}
 
function findNeighbors(aball: Ball2): Void {
    var val ;
    //1.calculate all neighbors
    var r_nball = group.lookup("{aball.slot + 10}") as Ball2;
    var d_nball = group.lookup("{aball.slot + 1}") as Ball2;
    var l_nball = group.lookup("{aball.slot - 10}") as Ball2;
    var u_nball = group.lookup("{aball.slot - 1}") as Ball2;
 
    //2. make a recursive call to check left,right,up and down
    if (aball.slot &lt;= 90 and not r_nball.checked) {
        r_nball.checked = true;
        val = check(aball, r_nball);
        if (val) {
            aball.checked = true;
            findNeighbors(r_nball);
        }
    }
    if (aball.slot mod 10 != 0 and not d_nball.checked) {
        d_nball.checked = true;
        val = check(aball, d_nball);
        if (val) {
            findNeighbors(d_nball);
        }
    }
    if (aball.slot &gt; 10 and not l_nball.checked) {
        l_nball.checked = true;
        val = check(aball, l_nball);
        if (val) {
            findNeighbors(l_nball);
        }
    }
    if (aball.slot mod 10 != 1 and not u_nball.checked) {
        u_nball.checked = true;
        val = check(aball, u_nball);
        if (val) {
            findNeighbors(u_nball);
        }
    }
}
 
function check(aball: Ball2, u_nball: Ball2): Boolean {
    var return_value: Boolean = false;
 
    if (checkColor(aball, u_nball)) {
        aball.effect = Glow {
            level: .4
            input: InnerShadow {
                choke: 0.05
                radius: 25
                color: Color.BLACK
            }
        }
        u_nball.effect = Glow {
            level: .4
            input: InnerShadow {
                choke: 0.05
                radius: 25
                color: Color.BLACK
            }
        }
        u_nball.initialSelect = true;
        return_value = true;
    }
    return return_value;
}
 
function checkColor(aball: Ball2, nball: Ball2): Boolean {
    var returnvalue: Boolean = false;
    if (aball.colorval == nball.colorval) {
        returnvalue = true;
    }
    return returnvalue;
}
 
function displayScore() {
    for (node in group.content) {
        var tball = (node as Ball2);
        if (tball.effect != null) {
            tball.score = "{score_count.intValue()}";
        }
    }
}
 
Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: KeyFrame {
        time: 30ms
        action: function () {
            var aball ;
            for (node in group.content) {
                aball = (node as Ball2);
 
                if (aball.flaggedfordeletion == true) {
                    for (i in [0..9]) {
                        fallStep();
                    }
                    for (i in [0..9]) {
                        shiftRightStep();
                    }
                }
            }
        }
    }
}.play();
 
class Ball2 extends CustomNode {
 
    var radius: Number;
    var vx: Number;
    var vy: Number;
    var slot: Integer;
    var initialSelect: Boolean;
    var flaggedfordeletion: Boolean;
    var checked: Boolean;
    var colorval ;
    var score: String;
    def acolor = [Color.ORANGE, Color.BLACK, Color.DODGERBLUE, Color.PURPLE];
    var random: Random = Random {
            };
 
    override function create() {
        colorval = random.nextInt(4);
        Group {content: [
                Circle {
                    translateX: bind vx
                    translateY: bind vy
                    radius: radius - 1
                    effect: DropShadow {
                        offsetX: 10
                        offsetY: 10
                        color: Color.BLACK
                        radius: 24
                    }
                    fill: RadialGradient {
                        radius: radius * .9;
                        focusX: radius * 0.2
                        focusY: radius * -8
                        proportional: false
                        stops: [
                            Stop {
                                offset: 0
                                color: Color.WHITE
                            }
                            Stop {
                                offset: 1
                                color: acolor[colorval];
                            }
                        ]
                    }
                    onMousePressed: function (event) {
                        score_count = 0;
                        //1. for every event check to see if the a group has already been identified and this is the second click to initiate deletion
                        if (initialSelect) {
                            var flagged = [];//this is to check to see if only one ball is select FIX ME
                            for (node in group.content) {
                                var aball = (node as Ball2);
                                if (aball.initialSelect == true) {
                                    insert aball into flagged;
                                }
                            }
                            if (sizeof flagged &gt; 1) {//this is to check to see if only one ball is select FIX ME
                                for (flag in flagged) {
                                    var f = (flag as Ball2);
                                    f.flaggedfordeletion = true;
                                }
                            }
                        } else { //2. if we have a group identified but the user doesn't want to delete that group ( by selecting another groups ball) then
                            // remove the intialSelects and effects from the first group
                            for (node in group.content) {
                                var aball = (node as Ball2);
                                if (aball.initialSelect == true) {
                                    aball.initialSelect = false;
                                    aball.effect = null;
                                    aball.score = "";
                                }
                            }
                        }
                        if (initialSelect == false) {
                            initialSelect = true;
 
                            findNeighbors(this);
 
                            for (node in group.content) {
                                var tball = (node as Ball2);
                                if (tball.effect != null) {
                                    score_count = score_count + 1;
                                }
                                if (tball.checked == true) {
                                    tball.checked = false;
                                }
                            }
                            if (score_count &gt; 9) {
                                score_count = score_count * 9
                            }
                            if (score_count == 8) {
                                score_count = score_count * 7
                            }
                            if (score_count == 7) {
                                score_count = score_count * 6
                            }
                            if (score_count == 6) {
                                score_count = score_count * 5
                            }
                            if (score_count == 5) {
                                score_count = score_count * 5
                            }
                            if (score_count == 4) {
                                score_count = score_count * 3
                            }
                            if (score_count == 3) {
                                score_count = score_count * 2
                            }
                            displayScore();
                        }
                    }
                }
                Text {
                    font: Font {size: 12
                    }
                    x: bind vx - 5,
                    y: bind vy
                    textAlignment: TextAlignment.LEFT
                    content: bind "{score}";
                }
            ]
        }
    }
}
var button = Group {
            translateY: 610
            translateX: 245
            content: [
                SwingButton {
                    text: "New Game"
                    action: function () {
                        initGroup()
                    }
                }
            ]
        }
var x = Stage {
            title: "Bubble Breaker"
            width: 600
            height: 700
            scene: Scene {
                fill: Color.GREY;
                content: bind [
                    button,
                    Text {
                        x: 220
                        y: 50
                        fill: Color.ORANGE
                        effect: Glow {
                            level: .8
                            input: InnerShadow {
                                choke: 0.05
                                radius: 2
                                color: Color.BLACK
                            }
                        }
                        font: Font {size: 30
                        }
                        content: "Score {totalScore}"
                    }
                    group
                ]
            }
        }

JavaFX Magic 8 Ball

Magic

webstartOriginally posted by me on ericonjavafx.com

package magicanswers;
 
import javafx.lang.FX;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import magicanswers.Oracle;
 
var oracle = Oracle { }
 
var mediaUrl:String = "http://ericonjavafx.com/Magic8Ball/Opium.wav";
if(FX.getArgument("mediaURL") != null) {
    mediaUrl = FX.getArgument("mediaURL").toString();
}
 
var music:MediaPlayer = MediaPlayer {
    volume:.4;
    media: Media {
        source: mediaUrl
    }
    autoPlay: true
    repeatCount:MediaPlayer.REPEAT_FOREVER
 }
 
 music.paused;
 
var stop_music:ImageView = ImageView {
    opacity: 1.0
    visible: true
    x: 0
    y: 675
    fitWidth:100
    preserveRatio: true
    blocksMouse:true
    image: Image {
        url: "{__DIR__}Sound.png"
    },
    onMousePressed: function(e) {
        if(music.paused){
            music.play();
        }else {
            music.pause();
        }
    }
};
 
var scene:Scene;
Stage {
 
	title: "Magic Eight Ball"
    scene:
    scene = Scene {
        height: 700
        width: 900
        fill:null;
        content: [
            Group{
                content:[  ImageView {
                        opacity: 1.0
                        visible: true
                        image: Image {
                            url: "{__DIR__}Background.png"
                        },
                        fitWidth:bind scene.width;
                        fitHeight:bind scene.height;
 
                    },oracle,
                    stop_music
                ]
            }
 
        ]
    }
};
 
package magicanswers;
 
import java.util.Random;
import javafx.animation.*;
import javafx.scene.*;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
 
public class MessageObject extends CustomNode {
    def rnd : Random = new Random();
    public var content:String;
    var image:Image =  Image {
        url: "{__DIR__}Triangle.png"
 
    }
    var imageView=ImageView {
        image: bind image
        visible: true
        cache:true}
 
    public override function create(): Node {
        return Group {
            content: [
                imageView,
                Text{
                    translateX: bind imageView.translateX + 31
                    translateY: bind imageView.translateY + 85
                    content:content;
                    font: Font {
                        size: 15
                    }
                    wrappingWidth: 100
                    textAlignment: TextAlignment.LEFT
                    fill:Color.LIGHTBLUE;
                },
            ]
            cache:true;
        }
    }
 
    public var fade = Timeline {
 
        def sx1 =.9;     def sx2 = .5;
        def sy1 =.9;     def sy2 = .5;
        def tx1 = 437;   def tx2 = 437 ;
        def ty1 = 300;   def ty2 = 300;
        def ro1 = this.rotate; def ro2 = rnd.nextDouble() * 400;
        keyFrames: [
            at(0s) {
            this.opacity    =&gt; .1 tween  Interpolator.LINEAR;
            this.scaleX     =&gt; sx2 tween Interpolator.LINEAR;
            this.scaleY     =&gt; sy2 tween Interpolator.LINEAR;
            this.translateX =&gt; tx2 tween Interpolator.LINEAR;
            this.translateY =&gt; ty2 tween Interpolator.LINEAR;
            this.rotate     =&gt; ro2 tween Interpolator.LINEAR;
            },
            at(2s)  {
            this.opacity    =&gt;.5 tween Interpolator.LINEAR;
            },
            at(4s) {
            this.opacity    =&gt; 1.0 tween Interpolator.LINEAR;
            this.scaleX     =&gt; sx1 tween Interpolator.LINEAR;
            this.scaleY     =&gt; sy1 tween Interpolator.LINEAR;
            this.translateX =&gt; tx1 tween Interpolator.LINEAR;
            this.translateY =&gt; ty1 tween Interpolator.LINEAR;
            this.rotate     =&gt; ro1 tween Interpolator.LINEAR;
            },
            at(8s)  {
            this.opacity    =&gt; .1 tween Interpolator.LINEAR;
            },
            KeyFrame {
                time: 8s
                action: function() {
                    delete this from (this.parent as Group).content;
                }
            }
        ]
    }
};
 
package magicanswers;
 
import java.util.Random;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.transition.AnimationPath;
import javafx.animation.transition.PathTransition;
import javafx.scene.CustomNode;
import javafx.scene.effect.light.DistantLight;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.Reflection;
import javafx.scene.Group;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.Node;
import javafx.scene.shape.ClosePath;
import javafx.scene.shape.HLineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
 
public class Oracle extends CustomNode {
    def rnd : Random = new Random();
    //it appears that 9 words is the limit
    var pool_of_answers = ["Who Knows","Absolutely","Maybe", "Yes", "No","Unclear at this time","Without a doubt"];
    var answer_to_question = "";
    var word:MessageObject;
    var node:Node;
    var flag_changeover:Boolean = false;
 
    def path = [
        MoveTo {
            x: 500,
            y:600 },
        HLineTo{
        x:525 },
        HLineTo{
        x:475}
        ClosePath{ } ];
 
    def animation = PathTransition
{
        node: this;
        path: AnimationPath.createFromPath(Path{
            elements: path});
        interpolate: true;
        duration: .3s
        repeatCount: 4
}
 
    var image:Image = Image {
        url: "{__DIR__}8ball.png"
        preserveRatio: true
        backgroundLoading: true
    }
    var image2:Image =  Image {
        url: "{__DIR__}8ball_view.png"
        preserveRatio: true
        backgroundLoading: true
    }
 
    public var changeover = Timeline {
        keyFrames: [
            at(0s) {
            this.opacity =&gt; .9 tween Interpolator.LINEAR;
 
            },
            at(2s) {
            this.opacity =&gt; 0 tween Interpolator.LINEAR;
 
            },
            at(4s) {
            this.opacity =&gt; 1.0 tween Interpolator.LINEAR;
            },
            KeyFrame {
                time: 2.0s
                action: function() {
                      image=image2;
                      flag_changeover = true;
 
                }
            }
            KeyFrame {
                time:4.2s
                action: function() {
                      generateMessage();
                }
            }
        ]
    }
 
    public override function create(): Node {
        node = Group {
            cache:true;
            content: [
                ImageView {
                    x: 250
                    y: 190
                    image: bind image
                    visible: true
                    cache:true
                }
 
            ] // content
            effect: Reflection {
                topOffset:0.1;
                fraction: 0.85
                topOpacity:.3
                bottomOpacity:0.1
                input:Lighting {
                    light: DistantLight {
                        azimuth: -135
                    }
                    surfaceScale: 9
                }
 
            }
            onMousePressed: function (event) {
                if(not flag_changeover){
                changeover.playFromStart();
                }
                else if(not animation.running and not word.fade.running  ){
                generateMessage();
                }
            }
 
        }
    }
 
      function generateMessage(){
                    animation.playFromStart();
                    answer_to_question = pool_of_answers[
                    rnd.nextInt(sizeof pool_of_answers)];
                    word = MessageObject {
                        content: bind answer_to_question
                    };
                    insert word into (this.parent as Group).content;
                        word.fade.play();
 
    }
 
}

JavaFX Vault Breaker Game

The 3 simple rules of the game are:

1. Break the 3 digit vault code with as few guesses as possible.

2. Observe that each guess provides feedback. For instance:

  • Each Black Circle indicates that one of the numbers guessed is correct and in the correct position.
  • Each Blue Circle indicates the one of the numbers guessed is correct but not in the correct position.

3. Have Fun!

You may start the game by clicking on the images below.

Please note that once the Vault has correctly been cracked….the game will reset in a few seconds.

vault

webstart

Originally posted by me on ericonjavafx.com

package vaultbreaker;
 
import vaultbreaker.Results;
import javafx.ext.swing.SwingButton;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.effect.Lighting;
import java.util.Random;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.Scene;
import javafx.stage.Stage;
 
var shift = 145; // from from scene.x and scene.y
var xshift = -50;
var score_count: Integer;
var random_number: String;
var group: Group = new Group;
var checkedGroup: Group;
var rs_group_array: Results[];
var rs_group: Group;
var guess: String;
var random = new Random();
 
function randomNumberGen():String{
  var x:String = String.valueOf((random.nextInt(999) * 100));
return "{x.substring(0, 3)}"};
 
function initGroup(){
rs_group_array =[];
random_number = randomNumberGen();
checkedGroup =  new Group;
rs_group = new Group;
guess ="";
score_count=0;
println(random_number);
}
initGroup();
 
var guessdisplay = Text {
    font: Font {
        size: 48
    }
    effect: Lighting {
        diffuseConstant: 1.0
        specularConstant: 1.0
        specularExponent: 20
        surfaceScale: 1.5
    }
 
    underline: true;
    fill: Color.SILVER;
    x: 100,
    y: 400
    content: bind guess;
}
 
var scoredisplay = Text {
    font: Font {
        size: 24
    }
    effect: Lighting {
        diffuseConstant: 1.0
        specularConstant: 1.0
        specularExponent: 20
        surfaceScale: 1.5
    }
    fill: Color.DODGERBLUE;
    x: 320,
    y: 40
    content: bind "Count: {score_count}";
}
 
for( i in [1..12]){
    insert NumberButton{
        value: "       {i}       ";
        id: "{i}";
    }
    into group.content;
}
 
function placeNumbers(){
 
    var b_1 = group.lookup("{1}") as NumberButton;
    b_1.vx = 100 + xshift;
    b_1.vy = 400 + shift;
    var b_2 = group.lookup("{2}") as NumberButton;
    b_2.vx = 175 + xshift;
    b_2.vy = 400 + shift;
    var b_3 = group.lookup("{3}") as NumberButton;
    b_3.vx = 250 + xshift;
    b_3.vy = 400 + shift;
    var b_4 = group.lookup("{4}") as NumberButton;
    b_4.vx = 100 + xshift;
    b_4.vy = 350 + shift;
    var b_5 = group.lookup("{5}") as NumberButton;
    b_5.vx = 175 + xshift;
    b_5.vy = 350 + shift;
    var b_6 = group.lookup("{6}") as NumberButton;
    b_6.vx = 250 + xshift;
    b_6.vy = 350 + shift;
    var b_7 = group.lookup("{7}") as NumberButton;
    b_7.vx = 100 + xshift;
    b_7.vy = 300 + shift;
    var b_8 = group.lookup("{8}") as NumberButton;
    b_8.vx = 175 + xshift;
    b_8.vy = 300 + shift;
    var b_9 = group.lookup("{9}") as NumberButton;
    b_9.vx = 250 + xshift;
    b_9.vy = 300 + shift;
    var b_10 = group.lookup("{10}") as NumberButton;
    b_10.vx = 92 + xshift;
    b_10.vy = 450 + shift;
    b_10.value = "CLEAR";
    var b_11 = group.lookup("{11}") as NumberButton;
    b_11.vx = 173 + xshift;
    b_11.vy = 450 + shift;
    b_11.value = "0";
    var b_12 = group.lookup("{12}") as NumberButton;
    b_12.vx = 252 + xshift;
    b_12.vy = 450 + shift;
    b_12.value = "ENTER";
 
}
 
placeNumbers();
 
function checkNumber(){
 
    score_count++;
    var blue: Integer = 0;
    var silver: Integer = 0;
 
    var result = Results{
        vx: 100,
        vy: 100,
        radius: 10
    }
 
    if(guess == random_number){
        println("GAME WON {score_count}");
        winner.playFromStart();
        initGroup();
        return;
    }
 
    var pos_1 = guess.substring(0,1);
    var pos_2 = guess.substring(1,2);
    var pos_3 = guess.substring(2,3);
 
    if(pos_1 == random_number.substring(0,1) or pos_1 == random_number.substring(1,2) or pos_1 == random_number.substring(2,3)){
        if(pos_1 == random_number.substring(0,1)){
            blue++;
        }else {
            silver++;
        }
 
    }
 
    if(pos_2 == random_number.substring(0,1) or pos_2 == random_number.substring(1,2) or pos_2 == random_number.substring(2,3)){
        if(pos_2 == random_number.substring(1,2)){
            blue++;
        }else {
            silver++;
        }
 
    }
 
    if(pos_3 == random_number.substring(0,1) or pos_3 == random_number.substring(1,2) or pos_3 == random_number.substring(2,3)){
        if(pos_3 == random_number.substring(2,3)){
            blue++;
        }else {
            silver++;
        }
 
    }
 
    for(b in [1..blue]){
        insert Color.BLACK into result.result_set;
    }
    for(s in [1..silver]){
        insert Color.DODGERBLUE into result.result_set;
    }
 
    result.guess = guess;
 
    insert result before rs_group_array[0];
 
    rs_group= new Group;
    var i = 0;
    var count = 0;
    for (node in rs_group_array){
        count++;
 
        node.translateX = 245;
        node.translateY = i;
        i=i + 29;
        if(count &lt; 20){
        insert node into rs_group.content;
        }
    }
 
}
 
var background_image = ImageView {
    image: Image {
        url: "{__DIR__}Image.jpg"
    }
fitWidth: 300
fitHeight: 300
    visible: true
}
var background_image2 = ImageView {
    image: Image {
        url: "{__DIR__}Image3.jpg"
    }
fitWidth: 300
fitHeight: 300
    visible: true
}
 
Stage {
    title: "Break the Vault"
    width: 465
    height: 670
    scene: Scene {
        content: bind[ group,guessdisplay,rs_group,background_image2,background_image,scoredisplay ]
        fill: LinearGradient {
            startX: 0.0
            startY: 400.0
            endX: 0.0
            endY: 700.0
            proportional:false;
            stops: [
                Stop {
                    color: Color.WHITE
                    offset: 0.0
                },
                Stop {
                    color: Color.DODGERBLUE
                    offset: 1.0
                },
 
            ]
        }
    }
}
 
class NumberButton extends CustomNode {
 
    var radius: Number;
    var vx: Number;
    var vy: Number;
    var value: String;
 
    override function create() {
 
        Group{
            content: [
                SwingButton {
                    translateX: bind vx;
                    translateY: bind vy;
                    text: bind value
                    action: function(){
                        if(id == "12" and (guess.length() == 3)){
                            checkNumber();
                            guess ="";
                        }
                        if(id == "10"){
 
                            guess = "";
                        }
 
                        if(guess.length() &lt; 3 and not (value   ==   "CLEAR") and not (value   ==   "ENTER")){
 
                            guess ="{guess}{value.trim()}"
                        }
                    }
                }
 
            ]
 
        }
    }
}
 
var winner = Timeline {
    keyFrames:[
        KeyFrame { time: 0s values:  background_image.opacity =&gt; 1  },
        KeyFrame { time: 0s values:  guess =&gt; ""  },
        KeyFrame { time: 1s values: background_image.opacity =&gt; 0 tween Interpolator.LINEAR },
        KeyFrame { time: 1s values:  guess =&gt; "You Win!"  },
        KeyFrame { time: 4s values: background_image.opacity =&gt; 0 tween Interpolator.LINEAR },
    ]
    autoReverse: true
    repeatCount:2;
}
 
package vaultbreaker;
 
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Ellipse;
import javafx.scene.text.Text;
import javafx.scene.text.Font;
import javafx.scene.effect.Lighting;
import javafx.scene.effect.Glow;
 
public class Results extends CustomNode {
 
    public var vx: Number;
    public var vy: Number;
    public var guess: String;
    public var radius: Number;
    public var result_set = [];
 
    override function create() {
    var r=2;
        Group{
            content: [
               Text {
                    font: Font {
                        size: 26
                    }
                    x: bind vx -20,
                    y: bind vy + 8
                    content: bind guess;
                    fill: Color.BLACK;
                    effect: Glow {
                        level: .4
                    }
            },
                Ellipse {
                    centerX: bind vx + 40,
                    centerY: bind vy,
                    radiusX: radius ,
                    radiusY: radius + r,
                    fill: bind result_set[0] as Paint;
 
                }
                Ellipse {
                    centerX: bind vx + 62,
                    centerY: bind vy,
                    radiusX: radius ,
                    radiusY: radius + r,
                    fill: bind result_set[1] as Paint;
 
                }
                Ellipse {
                    centerX: bind vx + 84,
                    centerY: bind vy,
                    radiusX: radius ,
                    radiusY: radius + r,
                    fill: bind result_set[2] as Paint;
 
                }
 ]
           effect: Lighting {
diffuseConstant: 1.0
specularConstant: 1.0
specularExponent: 20
surfaceScale: 1.5
            }
        }
    }
}

JavaFX Perspective Transform

JavaFXPerspective

webstart
Originally posted by me on ericonjavafx.com.
package perspective;
 
import javafx.scene.shape.Line;
import javafx.ext.swing.SwingButton;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.effect.PerspectiveTransform;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
 
 
 
 
 
def shift = 30; //This would be the shift from scene.x =0 scene.y=0
 
var uly:Integer = 40 + shift; //uly=  upper left y value
var ulx:Integer = 0 + shift;
var ury:Integer = 0 + shift;
var urx:Integer = 400 + shift;
var lly:Integer = 200 + shift;
var llx:Integer = 0 + shift;
var lry:Integer = 400 + shift;
var lrx:Integer = 400 + shift; //lrx=  lower right x value
 
def grid=Group{};
var nums = [0..40];
//sets the background grid
for(a_num in nums){
        insert Line{
        opacity:.3,
        startX:a_num * 10 + shift,
        endX:a_num * 10 + shift
        startY:shift
        endY:400 + shift} into grid.content;
insert Line{
        opacity:.3,
        startX:shift,
        endX:400 + shift,
        startY:a_num * 10 + shift,
        endY:a_num * 10 + shift} into grid.content;
}
 
//ULB = Upper Left Ball
var ULB = MyCircle {
 
    x: bind ulx with inverse,
    y: bind uly with inverse;
}
//URB = Upper Right Ball
var URB = MyCircle {
 
    x: bind urx with inverse,
    y: bind ury with inverse;
 
}
//LLB = Lower Left Ball
var LLB = MyCircle {
 
    x: bind llx with inverse,
    y: bind lly with inverse;
 
}
//LRB = Lower Right Ball
var LRB = MyCircle {
 
    x: bind lrx with inverse,
    y: bind lry with inverse;
 
}
 
Stage {
    title: "Perspective"
    width: 510
    height: 550
    scene: Scene {
        fill: Color.TRANSPARENT
        content: [
            Group{
                content:bind [
                   grid,
                    ImageView {
                        image: Image {
                            url: "{__DIR__}Image.jpg"
                        }
                        effect: bind PerspectiveTransform {
                            ulx: bind ulx
                            uly: bind uly
                            urx: bind urx
                            ury: bind ury
                            lrx: bind lrx
                            lry: bind lry
                            llx: bind llx
                            lly: bind lly
 
                        }
 
                        visible: true
                    }
                    ,MySlider{
                        x:0 + shift,
                        y:10,
 
                        vertical:false,
                        value:bind ulx with inverse
 
                    },MySlider{
                        x:200 + shift,
                        y:10,
                        vertical:false,
                        value:bind urx with inverse
 
                    }
                    MySlider{
                        x:10,
                        y:40,
                        rotate:180
                        value:bind uly with inverse,
                    vertical:true},
                    MySlider{
                        x:10,
                        y:250,
                        rotate:180
                        value:bind lly with inverse,
                    vertical:true},
                    MySlider{
                        x:435,
                        y:40,
                        rotate:180
                        value:bind ury with inverse,
                    vertical:true},
                    MySlider{
                        x:435,
                        y:250,
                        rotate:180
                        value:bind lry with inverse,
                    vertical:true},
                    MySlider{
                        x:10 + shift,
                        y:450,
                        vertical:false
                        value:bind llx with inverse}
                    MySlider{
                        x:210 + shift,
                        y:450,
                        vertical:false
                        value:bind lrx with inverse},
                ULB,
                URB,
                LLB,
                LRB,
                    SwingButton {
                        translateX:210
                        translateY: 470
                        text: "RESET"
                        action: function() {
                            uly = 40 + shift;
                            ulx= 0 + shift;
                            ury = 0 + shift;
                            urx = 400 + shift;
                            lly = 200 + shift;
                            llx= 0 + shift;
                            lry = 400 + shift;
                            lrx = 400 + shift;
 
                        }
                    }
 
                ]}
        ]
 
    }
}
 
package perspective;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.chart.part.PlotSymbol.Circle;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
 
public class MyCircle extends CustomNode {
def shift = 30; //This would be the shift from scene.x =0 scene.y=0
 public var y:Integer on replace {
        BBy = y;
    };
    var BBy:Number on replace {
        y = BBy as Integer;
     };
 
  public var x:Integer on replace {
        BBx = x;
    };
    var BBx:Number on replace {
        x = BBx as Integer;
    };
    public override function create(): Node {
        return Group {
            translateX: bind BBx
            translateY: bind BBy
            content: [Circle {
   //                 radius: 10,
                    fill: Color.RED
                }
            ]
 
            onMouseDragged:function(e:MouseEvent):Void{
 
                var tx = e.sceneX ;
                if(tx < 0 + shift) {
                    tx = shift;
                }
                if(tx > (420 + shift)  - this.boundsInLocal.width) {
                    tx = (420 + shift) - this.boundsInLocal.width;
                }
                BBx = tx;
 
                var ty = e.sceneY;
                if(ty < 0 + shift) {
                    ty = 0 + shift;
                }
                if(ty > (420 + shift) - this.boundsInLocal.height) {
                    ty = (420 + shift) - this.boundsInLocal.height;
                }
 
                BBy = ty;
 
            }
 
        };
    }
}
package perspective;
import javafx.ext.swing.SwingSlider;
import javafx.scene.CustomNode;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.text.Text;
 
 
 
public class MySlider extends CustomNode {
def shift = 30; //This would be the shift from scene.x =0 scene.y=0
    public var x=100;
    public var y=100;
    public var vertical=false;
    public var value=200;
 
    public override function create(): Node {
        return Group {
            content: [SwingSlider {
                    translateX:bind x
                    translateY:bind y
                    minimum: 0 + shift
                    maximum: 400 + shift
 
                    value: bind value with inverse
                    vertical: bind vertical
                }, Text {
                    x: bind x
                    y: bind y
                    rotate:
                    if (vertical)180 else 0;
                    content: bind "{value - shift}"
                }
 
            ]
        };
    }
}