Final Thoughts
We have created a simple game in JavaFX and my personal experience with JavaFX is very positive. I find it very intuitive to create graphical objects and timeline objects for animation. This is a great time saver and leads to better structured code and better looking graphics when comparing the code to the initial JavaSE implementation (please see Part 1).
Of course this game is only somewhat fun to play. Things that I would like to change are:
- Introduce Levels: Each Level would speed up the balls or add new balls
- Introduce bonus objects: Extra lives, things that make your ball or the enemy balls smaller or larger, etc.
- Tidy up the graphics: Think of a real game theme, instead of playing with balls
- Introduce sound effects
- Persist Highscore beyond the application life cycle
- …and many other things
If someone reading this article is interested in further developing this game, leave me a comment and I could check the sources into a public repository like kenai or sourceforge. Any other comments would also be appreciated.
Game Applet
You can drag the game onto your desktop by pressing the “Alt” key while you are dragging the game with your mouse.
And here is the webstart version.
Complete Tutorial Code
Main.fx
/*
* Main.fx
*
* Created on 15.10.2009, 17:36:19
*/
package myballgame;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.paint.Color;
import javafx.scene.Group;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Circle;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.layout.Tile;
import javafx.geometry.HPos;
/**
* @author Alexander Gnodtke
*/
def PLAYER_BALL_STEP = 4;
def MODE_GAME_OVER: String = "GAME_OVER";
def MODE_RUNNING: String = "RUNNING";
var mode:String = MODE_RUNNING;
var moveUp = false;
var moveDown = false;
var moveLeft = false;
var moveRight = false;
var scoreTime = 0;
var scoreMoves = 0;
var scoreBonus = 0;
var scoreTotal = 0;
var scoreHigh = 0;
var scoreArea: Group = Group {
content : [
Rectangle {
arcWidth: 20 arcHeight: 20
x: 290 y: 0
width: 120, height: 200
fill: Color.LIGHTGOLDENRODYELLOW
stroke: Color.DARKORANGE
strokeWidth: 3
},
Text {
font : Font {
size: 24
}
layoutX: 320 layoutY: 30
content: "Score"
},
Tile {
columns: 2
rows: 5
hgap: 5
vgap: 5
tileWidth: 50
hpos: HPos.LEADING
layoutX: 290 layoutY: 50
content: [
Text {
font : Font {
size: 12
}
content: "Time:"
},
Text {
font : Font {
size: 12
}
content: bind scoreTime.toString()
},
Text {
font : Font {
size: 12
}
content: "Moves:"
},
Text {
font : Font {
size: 12
}
content: bind scoreMoves.toString()
},
Text {
font : Font {
size: 12
}
content: "Bonus:"
},
Text {
font : Font {
size: 12
}
content: bind scoreBonus.toString()
},
Text {
font : Font {
size: 12
}
content: "Total:"
},
Text {
font : Font {
size: 12
}
content: bind scoreTotal.toString()
},
Text {
font : Font {
size: 12
}
content: "High:"
},
Text {
font : Font {
size: 12
}
content: bind scoreHigh.toString()
}
]
}
]
}
var playingField: Rectangle = Rectangle {
arcWidth: 20 arcHeight: 20
width: 280, height: 380
fill: Color.ANTIQUEWHITE
stroke: Color.DARKORANGE
strokeWidth: 3
}
var gameOverScreen: Group = Group{
visible:false
var r:Rectangle = Rectangle {
arcWidth: playingField.arcWidth arcHeight: playingField.arcHeight
width: playingField.width, height: playingField.height
fill: Color.ROSYBROWN
stroke: Color.DARKRED
strokeWidth: playingField.strokeWidth
}
content: [
r,
Text {
font : Font {
size: 24
}
x: 10, y: 50
content: "Game Over"
},
Text {
font : Font {
size: 20
}
x: 10, y: 80
content: "(press Enter to restart)"
}
]
}
var player: Circle = Circle {
translateX: 250, translateY:250
radius: 10
fill: Color.BLACK
}
var enemies : Enemy[] = for (i in [0..3]) {
var enemy:Enemy = Enemy {
translateX : randomEnemyInitPosition(), translateY:randomEnemyInitPosition()
}
enemy
};
var bonusTimeline: Timeline = Timeline {
repeatCount: 1
keyFrames : [
KeyFrame {
time : 3s
canSkip: false
}
]
}
var timeline: Timeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 30ms
canSkip: false
action: function() {
var playerMoved = false;
calculateBonusEnemy();
// Enemy
for (enemy in enemies)
enemy.calcPosition(playingField.boundsInLocal.minX,playingField.boundsInLocal.maxX,playingField.boundsInLocal.minY,playingField.boundsInLocal.maxY);
// Player
if (moveRight) {
var newX = player.translateX + PLAYER_BALL_STEP;
if (newX < playingField.boundsInLocal.maxX - player.radius - playingField.strokeWidth) {
playerMoved = true;
player.translateX = newX
}
}
if (moveLeft) {
var newX = player.translateX - PLAYER_BALL_STEP;
if (newX > playingField.boundsInLocal.minX + player.radius + playingField.strokeWidth) {
playerMoved = true;
player.translateX = newX
}
}
if (moveUp) {
var newY= player.translateY - PLAYER_BALL_STEP;
if (newY > playingField.boundsInLocal.minY + player.radius + playingField.strokeWidth) {
playerMoved = true;
player.translateY = newY
}
}
if (moveDown) {
var newY= player.translateY + PLAYER_BALL_STEP;
if (newY < playingField.boundsInLocal.maxY - player.radius - playingField.strokeWidth) {
playerMoved = true;
player.translateY = newY
}
}
// checkCollision
for (enemy in enemies) {
if (checkCircleCollision(player.translateX,player.translateY,player.radius,enemy.translateX,enemy.translateY,10.0)) {
if (not enemy.bonusMode) {
gameOver();
} else {
calculateNewScore(playerMoved,true);
}
} else {
calculateNewScore(playerMoved);
}
}
}
}
]
}
function calculateNewScore(addMoveScore:Boolean,addBonusScore:Boolean) {
scoreBonus += 1000;
calculateNewScore(addMoveScore);
}
function calculateNewScore(addMoveScore:Boolean) {
scoreTime += 5;
scoreMoves = if (addMoveScore) scoreMoves+5 else scoreMoves-10;
scoreTotal = scoreTime + scoreMoves + scoreBonus;
}
function calculateBonusEnemy() {
var bEnemy:Enemy = null;
for (enemy in enemies) {
if (enemy.bonusMode) {
bEnemy = enemy;
}
}
// None Bonus
if (bEnemy==null) {
if (javafx.util.Math.random()>0.95) {
// Change one to bonus
var i = (javafx.util.Math.ceil( enemies.size()*javafx.util.Math.random() )).intValue();
println("changing to bonus {i}");
enemies[i].fill(Color.CYAN);
enemies[i].bonusMode = true;
bonusTimeline.playFromStart();
}
} else {
// One Bonus
if (not bonusTimeline.running) { // min 3s in Bonus
if (javafx.util.Math.random()>0.5) { // Turn off bonus
bEnemy.fill(Enemy.DEFAULT_FILL);
bEnemy.bonusMode = false;
if (not bEnemy.bonusWasHit) {
scoreBonus -= 5000
}
bEnemy.bonusWasHit = false
} else {
// prolong bonus
bonusTimeline.playFromStart();
}
}
}
}
// Function called after collision
function gameOver():Void {
timeline.stop();
mode = MODE_GAME_OVER;
gameOverScreen.visible = true;
if (scoreTotal > scoreHigh)
scoreHigh = scoreTotal;
}
function initGame():Void {
initActors();
initScore();
mode = MODE_RUNNING;
gameOverScreen.visible = false
}
function initScore() {
scoreBonus = scoreMoves = scoreTime = scoreTotal = 0
}
// Function is used to initialize the actors i.e. player and enemies
// on the playing field
function initActors() {
player.translateX = 250;
player.translateY = 250;
for (enemy in enemies) {
enemy.translateX = randomEnemyInitPosition();
enemy.translateY = randomEnemyInitPosition();
}
}
// http://gpwiki.org/index.php/C:Collision_detection_between_two_circles
function checkCircleCollision(c1X:Number,c1Y:Number,c1R:Number,c2X:Number,c2Y:Number,c2R:Number):Boolean {
var distanceSquared = ((c1X - c2X) * (c1X - c2X)) + ((c1Y - c2Y) * (c1Y - c2Y));
var radiiSquared = (c1R + c2R) * (c1R + c2R);
if (radiiSquared > distanceSquared) {
return true
}
return false
}
function randomEnemyInitPosition():Integer {
var r = javafx.util.Math.random();
var r2 = javafx.util.Math.random();
((r * 100)+(r2*100)) as Integer
}
Stage {
title: "Ballgame"
scene: Scene {
fill: Color.CHOCOLATE;
width: 430, height: 400
content: Group {
focusTraversable: true
translateX: 10, translateY:10
content: [
playingField,
player,
enemies,
gameOverScreen,
scoreArea
]
onKeyPressed : function (e: KeyEvent){
if (mode==MODE_GAME_OVER) {
if (e.code == KeyCode.VK_ENTER) {
initGame();
timeline.playFromStart();
}
}
if (e.code == KeyCode.VK_LEFT) {
moveLeft = true;
}
if (e.code == KeyCode.VK_RIGHT) {
moveRight = true;
}
if (e.code == KeyCode.VK_UP) {
moveUp = true;
}
if (e.code == KeyCode.VK_DOWN) {
moveDown = true;
}
}
onKeyReleased : function (e: KeyEvent){
if (e.code == KeyCode.VK_LEFT) {
moveLeft = false;
}
if (e.code == KeyCode.VK_RIGHT) {
moveRight = false;
}
if (e.code == KeyCode.VK_UP) {
moveUp = false;
}
if (e.code == KeyCode.VK_DOWN) {
moveDown = false;
}
}
}
}
}
// Start game
timeline.playFromStart();
Enemy.fx
/*
* Enemy.fx
*
* Created on 03.10.2009, 13:59:33
*/
package myballgame;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.shape.Circle;
import javafx.scene.paint.Color;
/**
* @author Alexander Gnodtke
*/
public static def DEFAULT_FILL = Color.CRIMSON;
public class Enemy extends CustomNode {
public var bonusMode = false;
public var bonusWasHit = false; // Player hit in Bonus Mode
var radius = 10;
var moveUp = false;
var moveLeft = false;
var speedX = 0;
var speedY = 0;
var enemy:Circle;
override function create():Node {
// Enemy Speed
speedX = calcSpeed();
speedY = calcSpeed();
// Enemy initial Direction
moveUp = calcRandomBoolean();
moveLeft = calcRandomBoolean();
// Enemy figure
enemy = Circle {
radius: radius
fill: Color.CRIMSON
}
return enemy
}
public function fill(color:Color) {
enemy.fill = color;
}
function calcSpeed():Integer {
var r = javafx.util.Math.random();
if (r>0.66){
return 3
} else if (r<0.33) {
return 2
} else {
return 1
}
}
function calcRandomBoolean():Boolean {
if (javafx.util.Math.random()>0.5)
return true
else
return false
}
public function calcPosition(xMin:Integer,xMax:Integer,yMin:Integer,yMax:Integer) {
if (moveUp) {
var newY= translateY - speedY;
if (newY > yMin + radius)
translateY = newY
else
moveUp = false
} else {
var newY= translateY + speedY;
if (newY < yMax - radius)
translateY = newY
else
moveUp = true
}
if (moveLeft) {
var newX = translateX - speedX;
if (newX > xMin + radius)
translateX = newX
else
moveLeft = false
} else {
var newX = translateX + speedX;
if (newX < xMax - radius)
translateX = newX
else
moveLeft=true
}
}
}
A very good sample with a good explanation, thank you
I can’t seem to make it work on my machine.
Java Plug-in 1.6.0_17
Utilisation de la version JRE 1.6.0_17-b04 Java HotSpot(TM) Client VM
Répertoire d’accueil de l’utilisateur = C:\Users\Thierry
—————————————————-
c: effacer la fenêtre de la console
f: finaliser les objets de la file d’attente de finalisation
g: libérer la mémoire
h: afficher ce message d’aide
l: vider la liste des chargeurs de classes
m: imprimer le relevé d’utilisation de la mémoire
o: déclencher la consignation
q: masquer la console
r: recharger la configuration des politiques
s: vider les propriétés système et déploiement
t: vider la liste des threads
v: vider la pile des threads
x: effacer le cache de chargeurs de classes
0-5: fixer le niveau de traçage à
—————————————————-
security: property package.access value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.
security: property package.access new value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws
security: property package.access value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws
security: property package.access new value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws,com.sun.deploy
security: property package.access value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws,com.sun.deploy
security: property package.access new value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws,com.sun.deploy,com.sun.jnlp
security: property package.definition value null
security: property package.definition new value com.sun.javaws
security: property package.definition value com.sun.javaws
security: property package.definition new value com.sun.javaws,com.sun.deploy
security: property package.definition value com.sun.javaws,com.sun.deploy
security: property package.definition new value com.sun.javaws,com.sun.deploy,com.sun.jnlp
security: property package.access value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws,com.sun.deploy,com.sun.jnlp
security: property package.access new value sun.,com.sun.xml.internal.ws.,com.sun.xml.internal.bind.,com.sun.imageio.,com.sun.javaws,com.sun.deploy,com.sun.jnlp,org.mozilla.jss
security: property package.definition value com.sun.javaws,com.sun.deploy,com.sun.jnlp
security: property package.definition new value com.sun.javaws,com.sun.deploy,com.sun.jnlp,org.mozilla.jss
basic: Told clients applet is started
network: Created version ID: 1.6.0.13
network: Created version ID: 1.6
network: Created version ID: 1.6.0.17
network: Created version ID: 1.6
network: Created version ID: 1.6.0.17
network: Created version ID: 1.6
network: Created version ID: 1.6.0.17
network: Created version ID: 1.6
network: Created version ID: 1.6.0.17
network: Created version ID: 1.6
network: Entrée de cache introuvable [URL : http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp, version : null]
network: Entrée de cache introuvable [URL : http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp, version : null]
network: Entrée de cache introuvable [URL : http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp, version : null]
network: Connexion de http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp avec proxy=DIRECT
network: Connexion de http://blog.exprimeit.co.uk:80/ avec proxy=DIRECT
network: Code de réponse pour http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp : 200
network: Codage pour http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp : null
network: Réponse du serveur : (length: 1114, lastModified: Tue Oct 27 09:32:07 CET 2009, downloadVersion: null, mimeType: application/x-java-jnlp-file)
network: Téléchargement de la ressource : http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp
Content-Length : 1 114
Content-Encoding: null
network: Enregistrer l’URL http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp dans le fichier C:\Users\Thierry\AppData\LocalLow\Sun\Java\Deployment\cache\6.0\54\56c5f436-5275a9ff-temp
network: Suspendre la connexion à http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp
network: Cache: Enable a new CacheEntry: http://blog.exprimeit.co.uk/wp-content/MyBallGame_browser.jnlp
temp: new XMLParser with source:
temp:
MyBallGame
${application.vendor}
MyBallGame
temp:
returning ROOT as follows:
MyBallGame
${application.vendor}
MyBallGame
jnlp
network: CleanupThread used 153417 us
temp: returning LaunchDesc from XMLFormat.parse():
MyBallGame
${application.vendor}
MyBallGame
network: Entrée de cache introuvable [URL : http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp, version : null]
network: Entrée de cache introuvable [URL : http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp, version : null]
network: Connexion de http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp avec proxy=DIRECT
network: Connexion de http://localhost:8082/ avec proxy=DIRECT
java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at sun.net.NetworkClient.doConnect(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)
at com.sun.deploy.net.DownloadEngine.actionDownload(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getResourceCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCachedFile(Unknown Source)
at com.sun.javaws.jnl.LaunchDescFactory.buildDescriptor(Unknown Source)
at com.sun.javaws.jnl.LaunchDescFactory.buildDescriptor(Unknown Source)
at sun.plugin2.applet.JNLP2Manager.redirectLaunchDesc(Unknown Source)
at sun.plugin2.applet.JNLP2Manager.initialize(Unknown Source)
at sun.plugin2.main.client.PluginMain.initManager(Unknown Source)
at sun.plugin2.main.client.PluginMain.access$300(Unknown Source)
at sun.plugin2.main.client.PluginMain$2.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
network: Connexion de http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp avec proxy=DIRECT
network: Connexion de http://localhost:8082/ avec proxy=DIRECT
network: Entrée de cache introuvable [URL : http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp, version : null]
network: Entrée de cache introuvable [URL : http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp, version : null]
network: Connexion de http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp avec proxy=DIRECT
network: Connexion de http://localhost:8082/ avec proxy=DIRECT
java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(Unknown Source)
at java.net.PlainSocketImpl.connectToAddress(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at sun.net.NetworkClient.doConnect(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.openServer(Unknown Source)
at sun.net.www.http.HttpClient.(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.http.HttpClient.New(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.connect(Unknown Source)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at com.sun.deploy.net.HttpUtils.followRedirects(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doRequest(Unknown Source)
at com.sun.deploy.net.BasicHttpRequest.doGetRequestEX(Unknown Source)
at com.sun.deploy.net.DownloadEngine.actionDownload(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getResourceCacheEntry(Unknown Source)
at com.sun.deploy.net.DownloadEngine.getCachedFile(Unknown Source)
at com.sun.javaws.jnl.LaunchDescFactory.buildDescriptor(Unknown Source)
at com.sun.javaws.jnl.LaunchDescFactory.buildDescriptor(Unknown Source)
at sun.plugin2.applet.JNLP2Manager.redirectLaunchDesc(Unknown Source)
at sun.plugin2.applet.JNLP2Manager.initialize(Unknown Source)
at sun.plugin2.main.client.PluginMain.initManager(Unknown Source)
at sun.plugin2.main.client.PluginMain.access$300(Unknown Source)
at sun.plugin2.main.client.PluginMain$2.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
network: Connexion de http://localhost:8082/servlet/org.netbeans.modules.javafx.project.JnlpDownloadServlet/C%3A/Users/algnod/Documents/NetBeansProjects/MyBallGame/dist/MyBallGame_browser.jnlp avec proxy=DIRECT
network: Connexion de http://localhost:8082/ avec proxy=DIRECT
basic: JNLP2Manager.initialize(): JNLP not available: wp-content/MyBallGame_browser.jnlp
basic: exception : JNLP file error: wp-content/MyBallGame_browser.jnlp. Please make sure the file exists and check if “codebase” and “href” in the JNLP file are correct..
exception : JNLP file error: wp-content/MyBallGame_browser.jnlp. Please make sure the file exists and check if “codebase” and “href” in the JNLP file are correct..
java.io.FileNotFoundException: JNLP file error: wp-content/MyBallGame_browser.jnlp. Please make sure the file exists and check if “codebase” and “href” in the JNLP file are correct.
at sun.plugin2.applet.JNLP2Manager.loadJarFiles(Unknown Source)
at sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Exception : java.io.FileNotFoundException: JNLP file error: wp-content/MyBallGame_browser.jnlp. Please make sure the file exists and check if “codebase” and “href” in the JNLP file are correct.
security: Accès aux clés et au certificat dans le profil utilisateur Mozilla : null
@Thierry
Sorry, the xxx_browser.jnlp file was not set up correctly. The applet should now display properly.
Nonetheless, the WebStart link should have worked all along.
Code appears incomplete.
@botbotdingzip
Sorry about that, should be fixed now