Need some help in creating the basics of a JavaFX game

Been learning JavaFX, but still can’t get my head around nodes, in how to use them correctly for my game.

I’m looking into creating a basic game which will use 32x32 tiles, with gravity and collision.

I guess sorta like Virus effect

Anyone can help me to get started? I have looked around JavaFX site, google, etc but nothing I can really find that does such an example…

Have you looked at some of the samples? I know it’s a different type of a game, but it may help:
http://javafx.com/samples/BrickBreaker/index.html

Dmitri

Indeed I looked at the samples. I looked at that a few times. It really didn’t help my case.
Well I have found something on the tiles: http://silveiraneto.net/2009/01/06/javafx-easy-use-of-tiles/
I have basic gravity working now, and I think I know how to do collision so I’ll play around and see what I come up with…

Another pointer - not sure how useful for your case, but anyway:
http://newfoo.net/2009/03/24/game-design-with-javafx-production-suite.html

Dmitri

Yeah I had seen that game before.
But thanks.

zamm how far have you got in javafx?
i take it you can make a stage, scene and groupnode (up to drawing stuff).
are you getting stuff to move around?
have work out loading images and interaction?

hard to guess where to start.

Well I can basically show what I’ve done:

/**
 * @author Daniel
 */
    var upkey = false;
    var rightkey = false;
    var downkey = false;
    var leftkey = false;
    var leftMouse = false;
    var rightMouse = false;
    var bullet: Bullet[];

    var gamelogics = Timeline {
        repeatCount: Timeline.INDEFINITE
        keyFrames: KeyFrame {
            time: 1ms
            action: function() {
                if((robot.translateY + robot.height) < 450){
                    robot.translateY+=.4;
                }
                if(upkey){
                    robot.translateY-=.5;
                }
                else if(downkey){
                    robot.translateY-=.4;
                }
                if(rightkey){
                    robot.translateX += .2;
                }
                else if(leftkey){
                    robot.translateX -= .2;
                }
                for(b in bullet){
                    if(b.translateX > 5000){
                        delete b from bullet;
                    }
                    else
                        b.translateX+= 1;
                }
            }
        }
    }

def robot = new Robot;

public class RenderWindow extends Scene{

    init{
        this.content = [
            Group{
                onKeyPressed: function(e:KeyEvent){
                    if (e.code == KeyCode.VK_DOWN) {
                        downkey = true;
                    } else if (e.code == KeyCode.VK_UP) {
                        upkey = true;
                    }else if (e.code == KeyCode.VK_LEFT) {
                        leftkey = true;
                    }else if (e.code == KeyCode.VK_RIGHT) {
                        rightkey = true;
                    }
                } // onKeyPressed

                onKeyReleased: function(e: KeyEvent){
                    if (e.code == KeyCode.VK_DOWN) {
                        downkey = false;
                    } else if (e.code == KeyCode.VK_UP) {
                        upkey = false;
                    }else if (e.code == KeyCode.VK_LEFT) {
                        leftkey = false;
                    }else if (e.code == KeyCode.VK_RIGHT) {
                        rightkey = false;
                    }
                } // onKeyReleased
                onMousePressed: function(e:MouseEvent){
                    if(e.button == MouseButton.PRIMARY){
                        leftMouse = true;
                    }
                    if(e.button == MouseButton.SECONDARY){
                        rightMouse = true;
                    }
                };
                onMouseReleased: function(e:MouseEvent){
                    if(e.button == MouseButton.PRIMARY){
                        leftMouse = false;
                        var b = Bullet{
                            translateY : robot.translateY;
                            translateX : robot.translateX;
                        };
                        insert b into bullet;
                    }
                    if(e.button == MouseButton.SECONDARY){
                        rightMouse = false;
                    }
                };
                content: bind[
                    Rectangle {
                        x: 0,
                        y: 0,
                        width: 500,
                        height: 500,
                        fill: Color.LIGHTGRAY
                    },
                    robot
                    bullet
                ]
            }
        ];
        gamelogics.play();
    }
}
public class Robot extends CustomNode{

    public-read var width = 30;
    public-read var height = 30;

    override function create():Node{

        Rectangle { 
            x: 0,
            y: 0,
            width: 30,
            height: 30,
            fill: Color.STEELBLUE
            cache: true
        };
    };
}
public class Bullet extends CustomNode{

    var r = Random{};
    override function create():Node{
        Group{
            content: [
                Line {
                    var temp = r.nextInt(10);
                    startX: r.nextInt(10)
                    startY: temp
                    endX: r.nextInt(100)
                    endY: temp
                    strokeWidth: 1
                    stroke: Color.SLATEGRAY
                }
            ]
            effect:  MotionBlur {
                angle: 10
                radius: 20
            }
            cache: true
        }
    }
}
Stage {
    title: "Robot Game"
    width: 500
    height: 500
    scene: RenderWindow{}
}

Just working around with the basics first. If you have any tips to improve this or point out what I’ve done wrong, that would be great. Seems to lag a little when I fire a lot of bullets, and its not the motion blur that’s causing it.

I didn’t notice any lag, is my pc too strong :slight_smile: ?
I would say effects could slow down but you already said that it isn’t the case.

Try to set “canSkip” parameter of KeyFrame to true.

Well my laptop is new and a fairly good one.
After about 20 constant clicks it just major lags for me. It seems to draw off screen? But even then I still want to have 20 bullets on screen, when I add bots and what not.

Skip slows everything down, I guess it skips both frames and logic in my case, which is not what I want.

But onto better news I have collision working, bullets now can destroy objects(robots, other bullets, etc), a much better gravity.

good news :slight_smile:

this solves the problem:


var gamelogics = Timeline {
    repeatCount: Timeline.INDEFINITE
    keyFrames: KeyFrame {
        time: 10ms
        action: function() {
            if((robot.translateY + robot.height) < 450){
                robot.translateY+=4;
            }
            if(upkey){
                robot.translateY-=5;
            }
                else if(downkey){
                robot.translateY-=4;
            }
            if(rightkey){
                robot.translateX += 2;
            }
                else if(leftkey){
                robot.translateX -= 2;
            }
            for(b in bullet){
                if(b.translateX > 5000){
                    delete b from bullet;
                }
                    else
                b.translateX+= 10;
            }
        }
    }
}

Setting time parameter in keyframe is critical but I don’t know how to determine the most accurate value. I tried setting canSkip parameter in your game and saw that how it slows down the application. Something came to my mind, may be this can be used to calibrate the value of the time parameter. If this(canSkip) parameter changes the speed of your application too much it means many timecycles are skipped. If that doesn’t change the speed of the application too much than the value is appropriate, may be… only an idea.

I have improved it but, found this little piece of info: http://blogs.sun.com/jtc/entry/node_count_and_javafx_performance
Which I thought as much… Makes my game a lot harder to do now. I’m not making a crappy puzzle game for the contest :stuck_out_tongue:

I’m currently a little suck, I’m using fxz files for the art, which are nodes when loaded. If I wanted to use then as tiles, how would I do that?
It seems I can only use a node once, therefore my map wont fully print.

After a lot of searching I found I needed to do:

Duplicator.duplicate(node)

But does that duplicate the image too?

The Duplicator.duplicate() will duplicate a node as you mentioned. If the node has an ImageView node inside it its graph, it should duplicate the underlying image as well.

Node performance is slower than image based designs as pointed out in the article you linked. In some cases though, you don’t have to rely on making your entire design images. Sometimes you can greatly improve performance by simply having the JavaFX engine convert your nodes to a bitmaps by setting the cache property on your nodes to true. I have had good luck with that approach whenever I’m applying a lot of static effects to nodes that don’t need to be redrawn all the time.

[quote]The Duplicator.duplicate() will duplicate a node as you mentioned. If the node has an ImageView node inside it its graph, it should duplicate the underlying image as well.
[/quote]
What I mean is that would it share the image data , instead of making a copy and using more ram? If I use the same copy of the node for 100 tiles on a map, will it use more ram?

I have also made sure that the cache is set to true for all my static nodes.

This isn’t true for all 2D scenegraphs - Node-based systems can be much faster because dirty rectangles (invalid regions) can be computed automatically, therefore only changed regions of the screen need to be drawn (instead of drawing every pixel every frame). Of course it’s possible to compute changed-regions by hand in immediate-mode image systems, but who would want to do that?

The fact the JavaFX isn’t good with a large number of Nodes is a huge bug. Luckily trembovetski mentioned this will be fixed in JavaFX around the time of JavaOne.

Here’s a post about images and shapes performance, its for mobile, but seems to apply to desktop too: http://blogs.sun.com/michaelheinrichs/entry/best_practices_for_javafx_mobile2

Interestingly, tracking dirty regions (and bounds) could take lots of time. Just re-rendering every node from scratch can be faster.

Yes, if you have complicated nodes with effects, it’s better to cache them.

Dmitri

PulpCore tracks dirty regions, and it’s the single best optimization in the library. Even in some hardware-accelerated apps where overdraw can be a issue, it is worth it. Swing basically does it with the RepaintManager. JavaFX should do it too!

It does.

Dmitri