Processingjs — Java syntax without the browser plugin
Feb 5th
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
Jan 16th
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.
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&size=600x500"; var s:String ="http://maps.google.com/staticmap?markers=38,-77&zoom=7&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&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}&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}&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
Dec 18th
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 <= 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 > 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 > 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 > 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
Dec 18th
Originally 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 => .1 tween Interpolator.LINEAR; this.scaleX => sx2 tween Interpolator.LINEAR; this.scaleY => sy2 tween Interpolator.LINEAR; this.translateX => tx2 tween Interpolator.LINEAR; this.translateY => ty2 tween Interpolator.LINEAR; this.rotate => ro2 tween Interpolator.LINEAR; }, at(2s) { this.opacity =>.5 tween Interpolator.LINEAR; }, at(4s) { this.opacity => 1.0 tween Interpolator.LINEAR; this.scaleX => sx1 tween Interpolator.LINEAR; this.scaleY => sy1 tween Interpolator.LINEAR; this.translateX => tx1 tween Interpolator.LINEAR; this.translateY => ty1 tween Interpolator.LINEAR; this.rotate => ro1 tween Interpolator.LINEAR; }, at(8s) { this.opacity => .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 => .9 tween Interpolator.LINEAR; }, at(2s) { this.opacity => 0 tween Interpolator.LINEAR; }, at(4s) { this.opacity => 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
Dec 18th
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.
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 < 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() < 3 and not (value == "CLEAR") and not (value == "ENTER")){ guess ="{guess}{value.trim()}" } } } ] } } } var winner = Timeline { keyFrames:[ KeyFrame { time: 0s values: background_image.opacity => 1 }, KeyFrame { time: 0s values: guess => "" }, KeyFrame { time: 1s values: background_image.opacity => 0 tween Interpolator.LINEAR }, KeyFrame { time: 1s values: guess => "You Win!" }, KeyFrame { time: 4s values: background_image.opacity => 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
Dec 18th
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}" } ] }; } }