All the Interesting ThingsThis is a personal web log. All information posted here does not represent my employer. I do not speak for my employer. |
|
Sunday Jun 21, 2009
Pure Java Code to Invoke JavaFX Charting Features
From time to time, people asked questions like "how to call JavaFX from Java code?". After the release of JavaFX 1.0, I wrote a
post Interoperability between JavaFX and Java. I discussed three possible approaches to invoke JavaFX features from the Java side. These approaches were:
The third one seems the most elegant way to call JavaFX from Java. However, there is a drawback: the program should start from the JavaFX side. The reason is that it is simpler to use JavaFX code to instantiate the JavaFX classes which can be passed to Java code. Nevertheless, in some scenario, it would be better to start the program from the java side. For example, if you want to add in some JavaFX features to an existing large java application, it is better to have java code as the entry point. To solve this issue, I would introduce an approach for Pure Java Code to Call JavaFX Class. In fact, I am combining the essence of Approach 2 and 3 to create the below example. Let's say we want to invoke the latest charting functions of JavaFX 1.2 from the java code. We will first use the JavaFX reflection API to instantiate the JavaFX class. We then use it via its java interface. So we define a Java interface first.
/*
* JavaInterface.java
*
* @author Henry Zhang http://www.javafxgame.com
*/
package javatest;
public interface JavaInterface {
public void addData(String name, float data);
public void showChart();
}
The next step is to create a JavaFX class MyChart to implements this interface:
/*
* MyChart.fx
*
* @author Henry Zhang http://www.javafxgame.com
*/
package javatest;
import javafx.scene.chart.PieChart;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.scene.chart.PieChart3D;
public class MyChart extends JavaInterface {
var chartData : PieChart.Data[] = [];
public override function addData( l:String, v: Number):Void {
var labelString = l;
var data = PieChart.Data {
label : l
value : v
action: function() {
println("{labelString} clicked!");
}
} ;
insert data into chartData;
}
public override function showChart() : Void {
var chart =
PieChart3D {
data : chartData
pieThickness: 25
pieLabelFont: Font{ size: 9 };
pieToLabelLineOneLength: 10
pieToLabelLineTwoLength : 20
pieLabelVisible: true
pieValueVisible: true
translateY: -50
};
Stage {
title: "PieChart Window"
width: 520
height: 300
scene: Scene {
content: [
Text {
font : Font {
size : 16
}
x: 200
y: 20
content: "Pie Chart"
},
chart
]
}
}
}
}
The last thing is to write the java main class JavaTest.
/*
* JavaTest.java
* @author Henry Zhang http://www.javafxgame.com
*/
package javatest;
import javafx.reflect.FXClassType;
import javafx.reflect.FXLocal;
import javafx.reflect.FXLocal.Context;
import javafx.reflect.FXLocal.ObjectValue;
public class JavaTest {
public static void main(String args[]) {
Context context = FXLocal.getContext();
FXClassType instance = context.findClass("javatest.MyChart");
ObjectValue obj = (ObjectValue)instance.newInstance();
JavaInterface ji = (JavaInterface)obj.asObject();
String [] labels = {"January", "Febuary", "March", "April"};
int [] values = { 18, 20, 25, 37 };
for ( int i=0; i < values.length; i++ ) {
ji.addData(labels[i], values[i]);
}
ji.showChart();
}
}
In the above code, there are three lines for instantiating a JavaFX class via reflection:
Context context = FXLocal.getContext();
FXClassType instance = context.findClass("javatest.MyChart");
ObjectValue obj = (ObjectValue)instance.newInstance();
The next line is to convert the JavaFX instance into a java interface so that it can be used by Java code:
JavaInterface ji = (JavaInterface)obj.asObject();
If you are using NetBeans IDE, you can set javatest.JavaTest as the main class in your project properties(so that it can be the entry point of your program). Build this project you will get a javatest.jar. Running this program produces the below screenshot:
To run it from the command line, use the below command: javafx -jar javatest.jar Actually, you could do it in the purest java style by including all the JavaFX runtime stuffs, the command would look like this:
java -Djava.library.path="<path to javafx sdk lib>"
-classpath "<all javafx sdk jars>" -jar javatest.jar
Since there are many jar files used by the JavaFX, this purest java approach turns out to be very troublesome. I would rather use the javafx command, which is a wrapper of the above java command.
Please leave comments if you have any questions. Posted at 08:14PM Jun 21, 2009 by morningstar in JavaFX | Comments[8]
Thursday Jun 18, 2009
Pac-Man Game Demo-ed in JavaOne
JavaOne Speaker Stephen Chin told me that he demo-ed my Pac-man game in two of his sessions. Though I didn't attend the JavaOne event, I was happy to learn that the game was a huge hit in his sessions. The game he showed on JavaOne was a WidgetFX widget that I wrote to answer Jim Weaver's challenge. He asked me to write a widget before the J1 event. Stephen even promised to show it on the stage if I could finish in time. I think it was fun so I gave it a try. The APIs of WidgetFX was simple to use so I finished the widget in just 2 days. Thanks Steve for showing it on the big stage. The two JavaOne sessions were: Other JavaFX articles: Posted at 02:55AM Jun 18, 2009 by morningstar in JavaFX | Comments[1]
Saturday Jun 13, 2009
The Final Article on JavaFX Pac-man Game
This week, my last article of a series, "Writing the Pac-Man Game in JavaFX Part 5", is published. This article detailed the chasing algorithms of the ghosts. This is probably one of the most interesting things in the code. There are a few things we need to consider when designing an algorithm of the ghosts, such as effectiveness, randomness, simplicity. You can refer to the article about considerations on these aspects. An excerpt from the article is listed below in blue text. It discussed the choice of a proper algorithm. This algorithm not only serves as the chasing logic, it can also control the escaping behavior of the ghosts.
. . . . . .
In the figure, the ghost Blinky is moving into an intersection from the right to the left. When it reaches the intersection, it has three possible choices of its next movement: to go up, to go down and to continue heading left. Going down is not a valid move because it hits the border of the maze. So we need to compare the other two options. The below table shows the computation of the distance of the two possible moves:
As shown in the table, the distance from the intersection to the Pac-Man character is 13 (The distance between two adjacent dots is 1). If Blinky goes up, the distance is reduced to 12. If it heads left, the distance becomes 14. Therefore, going up seems a better choice for Blinky. In this way, Blinky should be able to get closer and closer to the Pac-Man and eventually catches him. Of course, this simple algorithm does not take into consideration for the walls in the maze.
For this reason, sometimes the calculated score does not in fact represent the shortest path. However,
this inaccuracy makes the ghosts appear "stupid" in the game, which is the randomness we want to achieve in
the behavior. So we are going to implement it in our code. We rewrite the class MoveDecision.
When the function evaluate() calculates a score, it takes in two arguments: the reference to
Pac-Man instance and whether the ghost is in a hollow state. The variable distance
is used to compute the score. If the ghost is going after the Pac-Man character, the score is
500-distance, which means a shorter distance yields a higher score. If the Pac-Man is
hunting the ghosts(when they are hollow), the score is caculated as 500+distance. This
makes the ghosts running away from the Pac-Man. Now that all the articles had been published and I hope you enjoyed reading them. The game was originally written in JavaFX 1.0, and was compatible with JavaFX 1.1. Because multi-inheritance was removed in JavaFX 1.2, there is some minor changes to the code. The code for JavaFX 1.2 can be download from JavaFX Demo Game Programming. You can now click on the below image to play the completed Pac-Man game, it is based on the newly released JavaFX 1.2 . With the improved performance, the game is much faster and can run very smoothly.
Related Articles: Posted at 03:38AM Jun 13, 2009 by morningstar in JavaFX |
Friday Jun 05, 2009
Latest Article on Writing the JavaFX Pac-Man Game
My latest article of a series, "Writing the Pac-Man Game in JavaFX Part 4", was out on June 4. The articles are getting more and more interesting now. In this article, the interaction between Pac-Man character and the ghosts was introduced in details. The article showed how to determine whether the Pac-man character and a ghost touched each other. A simplified equation was applied to achieve better performance. When Pac-man touches a ghost, he can eat it if the ghost is hollow. The ghost then is thrown back to the cage again. Otherwise, the ghost eats the Pac-man, at this moment, an animation of showing a dying Pac-Man appears. This is in fact a shrinking circle which disappears at the end of the animation. The animation is accomplished by the DyingPacMan class. The below figure depicts the animation process of the dying Pac-man character.
public class DyingPacMan extends Arc {
var timeline = Timeline {
repeatCount: 1
keyFrames: [
KeyFrame {
time: 600ms
action: function() {
// hide the pacMan character and ghosts before the animation
maze.pacMan.visible = false;
for ( g in maze.ghosts ) {
g.hide();
}
visible = true;
}
values: [ startAngle => 90, length=>360 ];
},
KeyFrame {
time: 1800ms
action: function() {
visible = false;
}
values: [ startAngle => 270 tween Interpolator.LINEAR,
length => 0 tween Interpolator.LINEAR ]
},
]
}
... code omitted ...
}
As you can see it in the code, there are two keyframes of the animation. Interpolations of two instance variables, startAngle and length, are involved during the animation. To better illustrate this process, the below figure shows the change of the shape against a timeline. Hope you enjoy reading the articles. You can use arrow keys to play the current version of the game. The ghosts are moving randomly which makes the game less challenging. In the next article, I will introduced a better algorithm. Try it by clicking the below screenshot:
Related Articles: Posted at 11:48PM Jun 05, 2009 by morningstar in JavaFX | |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||