Creating a Simple Game in JavaFX (Part 7)


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
        }
    }
}

Tags: , ,

5 Responses to “Creating a Simple Game in JavaFX (Part 7)”

  1. Simao Almeida says:

    A very good sample with a good explanation, thank you

  2. Thierry says:

    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

  3. admin says:

    @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.

  4. botbotdingzip says:

    Code appears incomplete.

  5. admin says:

    @botbotdingzip
    Sorry about that, should be fixed now

Leave a Reply