« Compiled JavaFX Script Now Speaks JSON | Main | Creating a Tetris Program (Part Two) in Compiled JavaFX Script »

February 22, 2008

Let's Create a Tetris Game in Compiled JavaFX Script

I thought it would be fun to spend a few posts creating a Tetris game in compiled JavaFX Script together.  Today I made a rough start on it, and if you promise not to laugh, I'll show you the humble beginnings.  Here's a screenshot of its current status:

Tetris_1

In Tetris, there are several types of tetrominoes, each having a letter that it resembles.  The four buttons on the left represent four of these shapes.  When you press one of these buttons, the corresponding tetromino appears at the top and begins moving down the screen.  When you click the Rotate button, the tetromino rotates to the right, and the Left/Right buttons move the tetromino left and right, respectively.

The code is contained in four FX program files, and needs some refactoring already. :-)  Before showing you the code in its current state, I'd like to point out a couple of helpful things: 

  • As explained in the Spinning Wheel post, the Key Frame animation syntax that you see here will become much less verbose as the JavaFX Script compiler team continues to address animation. 
  • JavaFX Script programs should always be designed with the UI binding to a model.  In this program, the model is represented in one class named TetrisModel, located in the FX file of the same name.  You may find it helpful to take a look the Creating a Compiled JavaFX Script Program with Multiple FX Source Files post to see a Hello World style program that has more than one FX file.  Please notice the package statments in this Tetris program, as that influences where you need to put the source files and how you build them.
  • You can obtain the JavaFX Compiler by following the instructions in the Obtaining the OpenJFX Script Compiler post.

The Source Code (so far)

Here's the main program, named TetrisMain.fx, that declaratively expresses the UI, and starts things up:

/*
*  TetrisMain.fx - The main program for a compiled JavaFX Script Tetris game
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to serve as a compiled JavaFX Script example.
*/
package tetris_ui;

import javafx.ui.*;
import javafx.ui.canvas.*;
import java.lang.System;
import tetris_model.*;

Frame {
  var model =
    TetrisModel {
      
    }
  var canvas:Canvas
  width: 480
  height: 500
  title: "TetrisJFX"
  background: Color.WHITE
  content:
    BorderPanel {
      center:
        canvas = Canvas {}
      bottom:
        FlowPanel {
          content: [
            Button {
              text: "I"
              action:
                function() {
                  canvas.content = [];
                  insert
                  TetrisShape {
                    model: model
                    shapeType: TetrisShapeType.I
                  }
                  into canvas.content; 
                  model.t.start();
                }
            },
            Button {
              text: "T"
              action:
                function() {
                  canvas.content = [];
                  insert
                  TetrisShape {
                    model: model
                    shapeType: TetrisShapeType.T
                  }
                  into canvas.content; 
                  model.t.start();
                }
            },
            Button {
              text: "L"
              action:
                function() {
                  canvas.content = [];
                  insert
                  TetrisShape {
                    model: model
                    shapeType: TetrisShapeType.L
                  }
                  into canvas.content; 
                  model.t.start();
                }
            },
            Button {
              text: "S"
              action:
                function() {
                  canvas.content = [];
                  insert
                  TetrisShape {
                    model: model
                    shapeType: TetrisShapeType.S
                  }
                  into canvas.content; 
                  model.t.start();
                }
            },
            Button {
              text: "Rotate"
              action:
                function() {
                  model.rotate90();
                }
            },
            Button {
              text: "Left"
              action:
                function() {
                  model.moveLeft();
                }
            },
            Button {
              text: "Right"
              action:
                function() {
                  model.moveRight();
                }
            }
          ]
        }
    }
  visible: true
  onClose:
    function():Void {
      System.exit(0);
    }
}

I made the TetrisShape class a custom graphical component.  Therefore, it is a subclass of the CompositeNode class, and overrides the composeNode function:

/*
*  TetrisShape.fx - A Tetris piece, configurable to the
*                   different shape types.  They are:
*                   I, J, L, O, S, T, and Z
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to serve as a compiled JavaFX Script example.

*/
package tetris_ui;

import javafx.ui.*;
import javafx.ui.canvas.*;
import java.awt.Point;
import java.lang.System;
import tetris_model.*;

class TetrisShape extends CompositeNode {
  private static attribute squareOutlineColor = Color.BLACK;
  private static attribute squareOutlineWidth = 2;
  private attribute squareColor;

  public attribute model:TetrisModel;
  public attribute shapeType:TetrisShapeType on replace {
    if (shapeType == TetrisShapeType.I) {
      squareLocs = [];
      insert new Point(0, model.SQUARE_SIZE * 1) into squareLocs;
      insert new Point(0, 0) into squareLocs;
      insert new Point(0, model.SQUARE_SIZE * 2) into squareLocs;
      insert new Point(0, model.SQUARE_SIZE * 3) into squareLocs;
      squareColor = Color.RED;
    }
    else if (shapeType == TetrisShapeType.T) {
      squareLocs = [];
      insert new Point(model.SQUARE_SIZE * 1, 0) into squareLocs;
      insert new Point(0, 0) into squareLocs;
      insert new Point(model.SQUARE_SIZE * 2, 0) into squareLocs;
      insert new Point(model.SQUARE_SIZE * 1, model.SQUARE_SIZE * 1) into squareLocs;
      squareColor = Color.GREEN;
    }
    else if (shapeType == TetrisShapeType.L) {
      squareLocs = [];
      insert new Point(0, model.SQUARE_SIZE * 1) into squareLocs;
      insert new Point(0, 0) into squareLocs;
      insert new Point(0, model.SQUARE_SIZE * 2) into squareLocs;
      insert new Point(model.SQUARE_SIZE * 1, model.SQUARE_SIZE * 2) into squareLocs;
      squareColor = Color.MAGENTA;
    }
    else if (shapeType == TetrisShapeType.S) {
      squareLocs = [];
      insert new Point(model.SQUARE_SIZE * 1, 0) into squareLocs;
      insert new Point(model.SQUARE_SIZE * 2, 0) into squareLocs;
      insert new Point(0, model.SQUARE_SIZE * 1) into squareLocs;
      insert new Point(model.SQUARE_SIZE * 1, model.SQUARE_SIZE * 1) into squareLocs;
      squareColor = Color.CYAN;
    }
  }
 
  private attribute squareLocs:Point[];
 
  public function composeNode():Node {
    return
      Group {
        transform: bind [
          Translate.translate(model.SQUARE_SIZE * model.tetrominoHorzPos,
                              (model.a / model.SQUARE_SIZE).intValue() * model.SQUARE_SIZE),
          Rotate.rotate(model.tetrominoAngle,
                        squareLocs[0].x + model.SQUARE_SIZE / 2,
                        squareLocs[0].y + model.SQUARE_SIZE / 2)
        ]
        content: [
          for (squareLoc in squareLocs) {
            Rect {
              x: bind squareLoc.x
              y: bind squareLoc.y
              width: bind model.SQUARE_SIZE
              height: bind model.SQUARE_SIZE
              fill: bind squareColor
              stroke: squareOutlineColor
              strokeWidth: squareOutlineWidth
            }
          }
        ]
      };
  }
}

The TetrisShapeType class defines the tetromino types:

/*
*  TetrisShapeType.fx - A Tetris shape type, which are
*                       I, J, L, O, S, T, and Z
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to serve as a compiled JavaFX Script example.

*/
package tetris_ui;

import javafx.ui.*;

class TetrisShapeType {
  public attribute id: Integer;
  public attribute name: String;

  public static attribute O =
    TetrisShapeType {id: 0, name: "O"};
  public static attribute I =
    TetrisShapeType {id: 1, name: "I"};
  public static attribute T =
    TetrisShapeType {id: 2, name: "T"};
  public static attribute L =
    TetrisShapeType {id: 3, name: "L"};
  public static attribute S =
    TetrisShapeType {id: 4, name: "S"};
}

And finally, here's a model class, named TetrisModel:

/*
*  TetrisModel.fx - The model behind the Tetris UI
*
*  Developed 2008 by James L. Weaver (jim.weaver at lat-inc.com)
*  to serve as a compiled JavaFX Script example.

*/
package tetris_model;

import javafx.ui.animation.*;
import java.lang.System;
import com.sun.javafx.runtime.PointerFactory;

public class TetrisModel {
  public static attribute SQUARE_SIZE = 20;
 
  public attribute a:Integer;
  private attribute pf = PointerFactory {};
  private attribute bpa = bind pf.make(a);
  private attribute pa = bpa.unwrap();
  private attribute interpolate = NumberValue.LINEAR;
  public attribute t =
    Timeline {
      keyFrames: [
        KeyFrame {
          keyTime: 0s;
          keyValues:
            NumberValue {
              target: pa;
              value: 0;
              interpolate: bind interpolate
            }
        },
        KeyFrame {
          keyTime: 20s;
          keyValues:
            NumberValue {
              target: pa;
              value: 370
              interpolate: bind interpolate
            }
        }
      ]
    };
  public attribute tetrominoAngle:Number;
  public attribute tetrominoHorzPos:Number = 10;
 
  public function rotate90():Void {
    (tetrominoAngle += 90) % 360;
  }

  public function moveLeft():Void {
    if (tetrominoHorzPos > 0) {
      tetrominoHorzPos--;
    }
  }
 
  public function moveRight():Void {
    if (tetrominoHorzPos < 20) { //TODO:Replace 10 with a calculated number
      tetrominoHorzPos++;
    }
  }

}

Compile and execute this example, and examine the code.  I'll get busy making it behave a little more like a Tetris game, and show you some progress in the next post.  Please feel free to get ahead of me, and make your own version!

JavaFX Script Boot Camp Registration Now Open!

Javafxpertbootcamp300x250bannerindy

I will be offering a 2.5 day JavaFX Script day "boot camp" on Wednesday, April 9 through Friday, April 11, 2008 (ending at noon) in Indianapolis, Indiana.  By the way, I'm scouting out the next location, so if you have suggestions for where I should offer a future BootCamp please let me know!

Regards,
Jim Weaver
JavaFX Script: Dynamic Java Scripting for Rich Internet/Client-side Applications

Immediate eBook (PDF) download available at the book's Apress site

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00e54f133d69883400e55068d2488833

Listed below are links to weblogs that reference Let's Create a Tetris Game in Compiled JavaFX Script:

Comments

What about San Diego California for your next location? We have a great JUG

http://ww.sdjug.com/

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been posted. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

My Photo

Upcoming Speaking Engagements:


  • Stephen Chin and Jim Weaver speaking about JavaFX Platform

  • Speaking on JavaFX and Java at Øredev in Malmö, Sweden on 2-6 November, 2009

Upcoming JavaFX Training:


  • Developing Secure, Rich Internet Applications Hosted on a Variety of Clients Using JavaFX Technology

Enter your email address:

Delivered by FeedBurner

Available now as early access eBook


  • Click book image above to obtain eBook

Twitter Updates

    follow me on Twitter

    Affiliations:

    DZone Links:


    July 2009

    Sun Mon Tue Wed Thu Fri Sat
          1 2 3 4
    5 6 7 8 9 10 11
    12 13 14 15 16 17 18
    19 20 21 22 23 24 25
    26 27 28 29 30 31  

    Disclaimer:

    • By reading this site, you are agreeing that under no circumstances will Veriana Networks, Inc. or its affiliates be responsible for (1) any information contained on or omitted from the site, (2) any person's reliance on any such information, whether or not the information is correct, current or complete, (3) the consequences of any action you or any other person takes or fails to take, whether or not based on information provided by or as a result of the use of the sites.