DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
  1. DZone
  2. Coding
  3. Java
  4. Creating a Tetris Program (Part Two) in Compiled JavaFX Script

Creating a Tetris Program (Part Two) in Compiled JavaFX Script

James Weaver user avatar by
James Weaver
·
Feb. 24, 08 · Interview
Like (0)
Save
Tweet
Share
15.08K Views

Join the DZone community and get the full member experience.

Join For Free

this is the second part of a mini-series in which we're creating a tetris game in compiled javafx script together.  if you haven't already, please take a look at the let's create a tetris game in compiled javafx script post to get up to speed.

here's a screen shot of the executing program in its current state:

tetris_2

as you can see, i've made a few changes to the ui, making it look a little more like a tetris game.  i also refactored some of the code, introduced a new class to represent the playing field, moved the tetrisshapetype class to the tetris_model package, and added some functionality.

compile and run the code that you see below, and click the play button when the screen shown above appears.  this causes one of the seven tetromino types to begin falling down the playing field.  clicking the rotate button rotates the tetromino clockwise, clicking the left button moves it to left, and clicking the right button moves it to the right.  when the tetromino arrives at the bottom, it disappears and a new randomly chosen tetromino shape begins falling.  to exit the program, close the window.

in its current state, the program doesn't have all of the functionality required in a tetris game (for example, the tetrominoes don't stack up).  we'll get there, and hopefully we'll all learn more about developing javafx script applications in the process.  here's the current source code:

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.lightgrey
content:
borderpanel {
center:
flowpanel {
content: [
canvas {
content:
tetrisplayingfield {
model: model
}
}
]
}
bottom:
flowpanel {
content: [
button {
text: "play"
action:
function() {
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);
}
}

the tetrisshape custom graphical component.  by the way, i refactored the big ugly i f/else statement from this class:

/*
* 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 = 1;
private attribute squarecolor;

public attribute model:tetrismodel;

public attribute shapetype:tetrisshapetype on replace {
squarelocs =
for (block in shapetype.squarepositions) {
new point(block.x * model.square_size,
block.y * model.square_size)
};
squarecolor = shapetype.squarecolor;
};

private attribute squarelocs:point[];

public function composenode():node {
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: bind [
for (squareloc in squarelocs) {
rect {
x: squareloc.x
y: squareloc.y
width: bind model.square_size
height: bind model.square_size
fill: bind squarecolor
stroke: squareoutlinecolor
strokewidth: squareoutlinewidth
}
}
]
};
}
}

the newly introduced tetrisplayingfield custom graphical component that manages the area in which the tetrominoes fall:

/*
* tetrisplayingfield.fx -
* a custom graphical component that is the ui for the
* playing field.
*
* 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.*;

class tetrisplayingfield extends compositenode {
public attribute model:tetrismodel;

public function composenode():node {
group {
content: [
rect {
x: 0
y: 0
width: model.num_cols * model.square_size
height: model.num_rows * model.square_size
strokewidth: 1
stroke: color.black
fill: color.white
},
tetrisshape {
model: model
shapetype: bind model.activeshapetype
}
]
}
}
}

the tetrisshapetype class defines the tetromino types, and i decided that it is really part of the model, so i moved it to the tetris_model package:

/*
* 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_model;

import javafx.ui.*;
import java.awt.point;
import java.lang.math;

/**
* this class contains the model information for each type
* of tetromino (tetris piece).
*/
public class tetrisshapetype {
public attribute id: integer;
public attribute name: string;

/**
* a sequence containing positions of each square in a
* tetromino type. the first element in the sequence is
* the one around which the tetromino will rotate.
* note that the "o" tetromino type doesn't rotate.
*/
public attribute squarepositions:point[];

public attribute allowrotate:boolean = true;

public attribute squarecolor:color;

/** the "i" shape (four squares in a straight line) */
public static attribute i =
tetrisshapetype {
id: 1
name: "i"
squarepositions: [
new point(1, 0),
new point(0, 0),
new point(2, 0),
new point(3, 0)
]
squarecolor: color.red
};

/** the "t" shape (looks like a stout "t") */
public static attribute t =
tetrisshapetype {
id: 2
name: "t"
squarepositions: [
new point(1, 0),
new point(0, 0),
new point(2, 0),
new point(1, 1)
]
squarecolor: color.green
};

/** the "l" shape (looks like an "l") */
public static attribute l =
tetrisshapetype {
id: 3
name: "l"
squarepositions: [
new point(1, 0),
new point(0, 0),
new point(2, 0),
new point(0, 1)
]
squarecolor: color.magenta
};

/** the "j" shape (looks sort of like a "j", but
* more like a backwards "l") */
public static attribute j =
tetrisshapetype {
id: 4
name: "j"
squarepositions: [
new point(1, 1),
new point(1, 0),
new point(1, 2),
new point(0, 2)
]
squarecolor: color.yellow
};

/** the "s" shape (looks sort of like an "s") */
public static attribute s =
tetrisshapetype {
id: 5
name: "s"
squarepositions: [
new point(1, 0),
new point(2, 0),
new point(0, 1),
new point(1, 1)
]
squarecolor: color.cyan
};

/** the "z" shape (looks sort of like an "z") */
public static attribute z =
tetrisshapetype {
id: 6
name: "z"
squarepositions: [
new point(1, 0),
new point(0, 0),
new point(1, 1),
new point(2, 1)
]
squarecolor: color.orange
};

/** the "o" shape (looks sort of like an "o", but
* more like a square) */
public static attribute o =
tetrisshapetype {
id: 7
name: "o"
squarepositions: [
new point(0, 0),
new point(0, 1),
new point(1, 0),
new point(1, 1)
]
squarecolor: color.blue //todo:research official color
allowrotate: false
};

/**
* a sequence of the shape types for use in generating a
* random shape type.
*/
private static attribute allshapetypes:tetrisshapetype[];

/**
* a function that returns a random tetrisshapetype
*/
public static function randomshapetype():tetrisshapetype {
if (sizeof allshapetypes <= 0) {
insert i into allshapetypes;
insert t into allshapetypes;
insert l into allshapetypes;
insert j into allshapetypes;
insert s into allshapetypes;
insert z into allshapetypes;
insert o into allshapetypes;
}
allshapetypes[(math.random() * sizeof allshapetypes) as integer]
}
}

and finally, here's the tetrismodel class.  i added several attributes to this class, mainly to serve as model variables for the new tetrisplayingfield class:

/*
* 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;
import java.lang.double;

public class tetrismodel {
/** size of each tetromino in pixels */
public static attribute square_size = 20;

/** number of rows in the playing field */
public static attribute num_rows = 20;

/** number of columns in the playing field */
public static attribute num_cols = 10;

/**
* sequence of objects that represent the
* type of shapes in each playing field cell
*/
public attribute fieldcells:tetrisshapetype[];

/**
* the active tetromino shape type.
*/
public attribute activeshapetype:tetrisshapetype;

public attribute running:boolean = true;
public attribute a:integer on replace {
if (a >= stopvalue) {
activeshapetype = tetrisshapetype.randomshapetype();
tetrominoangle = 0;
}
};
private attribute pf = pointerfactory {};
private attribute bpa = bind pf.make(a);
private attribute pa = bpa.unwrap();
private attribute interpolate = numbervalue.linear;
private attribute stopvalue = 370;
public attribute t =
timeline {
keyframes: [
keyframe {
keytime: 0s;
keyvalues:
numbervalue {
target: pa;
value: 0;
interpolate: bind interpolate
}
},
keyframe {
keytime: 10s;
keyvalues:
numbervalue {
target: pa;
value: stopvalue
interpolate: bind interpolate
}
}
]
repeatcount: double.positive_infinity
};
public attribute tetrominoangle:number;
public attribute tetrominohorzpos:number = (num_cols / 2) as integer;

public function rotate90():void {
if (activeshapetype.allowrotate) {
(tetrominoangle += 90) % 360;
}
}

public function moveleft():void {
if (tetrominohorzpos > 0) {
tetrominohorzpos--;
}
}

public function moveright():void {
//todo: need to allow pieces to bump up against the
// right side. for now, hardcode 3.
if (tetrominohorzpos < num_cols - 3) {
tetrominohorzpos++;
}
}
}

some remaining functionality

there is still much to do in order to make this a fully functioning tetris game.  for example, the model needs to:

  • keep track of which cells in the playing field are empty, and which hold tetromino debris.
  • know when a tetromino has landed on the bottom (or on tetromino debris), so that it can stop falling.
  • delete the tetromino debris from a filled up row, and allow the tetromino debris lying above to collapse into the vacated row.
  • use the rotation state of the currently falling tetromino to allow it to accurately bump up against the left and right sides.

also, functionality needs to be added that displays the score, shows the next tetromino shape to fall, etc.  have fun running, and examining, this code!

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

JavaFX Script JavaFX

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Distributed Tracing: A Full Guide
  • Kubernetes-Native Development With Quarkus and Eclipse JKube
  • 19 Most Common OpenSSL Commands for 2023
  • What Are the Different Types of API Testing?

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: