Wednesday, June 24, 2009

Space Invaders FX : Part 1

Ohk, so I wrote this simple game in JavaFX, named it Space Invaders FX ..

The entire source code for the game can be downloaded from here.

The source code has three files, tank.fx, monster.fx and Main.fx. In this post we will talk about tank.fx. This class controls the movements, shooting and everything else to do with the tank. Here it is:
/*
* tank.fx
*
* Created on Jun 21, 2009, 9:19:12 AM
*/

package spaceinvadersfx;

import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.scene.CustomNode;
import javafx.scene.Node;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.Group;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Polygon;
import javafx.scene.paint.Color;
import javafx.animation.Timeline;
import javafx.animation.KeyFrame;
import javafx.animation.Interpolator;

/**
* @author Sagar Jauhari
*/

public class tank extends CustomNode {

var monster = monsters{};

var fireAgain = true;

var tankX: Integer;
var tankY = 400;

var bulletX: Integer;
var bulletY = 400;

var visiblity = false;

var image = ImageView {
x: bind tankX, y: tankY
image: Image {
url: "{__DIR__}resources/tank 50X50.png"
}
};
var bg = ImageView {
onKeyPressed: function( e: KeyEvent ) {
if(e.code == KeyCode.VK_LEFT){
if(tankX >= 50){
tankX-=50;
}
}
if(e.code == KeyCode.VK_RIGHT){
if(tankX <= Main.screenWidth - 100){
tankX+=50;
}
}

}
onMouseClicked: function( e: MouseEvent ):Void {
fire();
}


image: Image {
url: "{__DIR__}resources/bg.jpg"
}
};
var bullet = Polygon {
visible: bind visiblity
translateX: bind bulletX
translateY: bind bulletY
points : [ 0,7, 5,0, 10,7, 10,15, 5,5, 0,15 ]
fill: Color.YELLOW
stroke: Color.RED
}

var timeline = Timeline {
repeatCount: 1
keyFrames : [
at (0s) {bulletX => tankX+20; bulletY => tankY; visiblity => true; fireAgain=> false },
at (1s) {bulletY=> -20; visiblity => true; fireAgain=> true}
]
}
var colissionTimeline = Timeline {
repeatCount: Timeline.INDEFINITE
keyFrames : [
KeyFrame {
time : 0.1s
action: function(){colissionDetect()}
}
]
}


public function fire(){
if(fireAgain){
timeline.playFromStart();
}
}

public function colissionDetect(){
if(monster.intersects(bulletX,bulletY,10,15)){
monster.isDead();
}

}

public override function create() :Node{
bg.requestFocus();
colissionTimeline.play();
return{
Group{
content: bind[bg,image,bullet,monster]
}
}
}
}


Understanding the code:
  1. First of all, we make an image of tank of 50X50px. Here's the image I made in GIMP:
  2. Next, we import it for using:
        var image = ImageView {
    x: bind tankX, y: tankY
    image: Image {
    url: "{__DIR__}resources/tank 50X50.png"
    }
    };

  3. Now we put a background image and add all the mouse and keyboard triggers to it.
     var bg = ImageView {
    onKeyPressed: function( e: KeyEvent ) {
    if(e.code == KeyCode.VK_LEFT){
    if(tankX >= 50){
    tankX-=50;
    }
    }
    if(e.code == KeyCode.VK_RIGHT){
    if(tankX <= Main.screenWidth - 100){
    tankX+=50;
    }
    }

    }
    onMouseClicked: function( e: MouseEvent ):Void {
    fire();
    }


    image: Image {
    url: "{__DIR__}resources/bg.jpg"
    }
    };


  4. Now we come to the more interesting part: the shooting! :). To represent a bullet, I made a polygon. The idea is to traverse this polygon from bottom to top by binding its y coordinate to a variable and linearly varying that variable with time using the Timeline class. Initially the bullet is invisible, then, while shooting it becomes visible and then again it becomes invisible. This gives the impression that multiple bullets are being shot contrary to the fact that actually, it is the same bullet again and again! Also, there is a constraint that at any point of time, only one bullet is in the scene. This is managed by the 'fireAgain' flag. See here:
        var bullet = Polygon {
    visible: bind visiblity
    translateX: bind bulletX
    translateY: bind bulletY
    points : [ 0,7, 5,0, 10,7, 10,15, 5,5, 0,15 ]
    fill: Color.YELLOW
    stroke: Color.RED
    }

    var timeline = Timeline {
    repeatCount: 1
    keyFrames : [
    at (0s) {bulletX => tankX+20; bulletY => tankY; visiblity => true; fireAgain=> false },
    at (1s) {bulletY=> -20; visiblity => true; fireAgain=> true}
    ]
    }


  5. Finally, there's this function called fire() which fires the bullet.
        public function fire(){
    if(fireAgain){
    timeline.playFromStart();
    }
    }

So this was most of what was done with the tank. The collision detection with the 'monster' and some other snippets not explained here will be explained in the next post when we discuss the 'monsters.fx' class.

3 comments:

  1. great work, like the part where you explain the code..

    way to go! cheers.. :)

    ReplyDelete
  2. hey dude, u may not know me, but i am bitsgian too, 2009 passout and have great interest in java,linux just like u, great work dude... got a good source of inspiration from u :).

    Keep going...
    Vidyuth

    ReplyDelete
  3. thanks Mohit, thanks Viduth for the compliments. You all motivate me ! :)

    ReplyDelete

Any query, doubt, problem or feedback is heartily invited.

Note: Only a member of this blog may post a comment.