Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon

Flash Game Development: Creation of a Complete Tetris Game

Save for later
  • 10 min read
  • 25 Mar 2011

article-image

Tetris features shapes called tetrominoes, geometric shapes composed of four squared blocks connected orthogonally, that fall from the top of the playing field. Once a tetromino touches the ground, it lands and cannot be moved anymore, being part of the ground itself, and a new tetromino falls from the top of the game field, usually a 10x20 tiles vertical rectangle. The player can move the falling tetromino horizontally and rotate by 90 degrees to create a horizontal line of blocks. When a line is created, it disappears and any block above the deleted line falls down. If the stacked tetrominoes reach the top of the game field, it's game over.

Defining game design


This time I won't talk about the game design itself, since Tetris is a well known game and as you read this article you should be used to dealing with game design.

By the way, there is something really important about this game you need to know before you start reading this article. You won't draw anything in the Flash IDE. That is, you won't manually draw tetrominoes, the game field, or any other graphic assets. Everything will be generated on the fly using AS3 drawing methods.

Tetris is the best game for learning how to draw with AS3 as it only features blocks, blocks, and only blocks.

Moreover, although the game won't include new programming features, its principles make Tetris the hardest game of the entire book. Survive Tetris and you will have the skills to create the next games focusing more on new features and techniques rather than on programming logic.

Importing classes and declaring first variables


The first thing we need to do, as usual, is set up the project and define the main class and function, as well as preparing the game field.

Create a new file (File | New) then from New Document window select Actionscript 3.0. Set its properties as width to 400 px, height to 480 px, background color to #333333 (a dark gray), and frame rate to 30 (quite useless anyway since there aren't animations, but you can add an animated background on your own). Also, define the Document Class as Main and save the file as tetris.fla.

Without closing tetris.fla, create a new file and from New Document window select ActionScript 3.0 Class. Save this file as Main.as in the same path you saved tetris.fla. Then write:

package {
import flash.display.Sprite;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
public class Main extends Sprite {
private const TS_uint=24;
private var fieldArray:Array;
private var fieldSprite:Sprite;
public function Main() {
// tetris!!
}
}
}




We already know we have to interact with the keyboard to move, drop, and rotate tetrominoes and we have to deal with timers to manage falling delay, so I already imported all needed libraries.

Then, there are some declarations to do:

private const TS_uint=24;




TS is the size, in pixels, of the tiles representing the game field. It's a constant as it won't change its value during the game, and its value is 24. With 20 rows of tiles, the height of the whole game field will be 24x20 = 480 pixels, as tall as the height of our movie.

private var fieldArray:Array;




fieldArray is the array that will numerically represent the game field.

private var fieldSprite:Sprite;




fieldSprite is the DisplayObject that will graphically render the game field.

Let's use it to add some graphics.

Drawing game field background


Nobody wants to see an empty black field, so we are going to add some graphics. As said, during the making of this game we won't use any drawn Movie Clip, so every graphic asset will be generated by pure ActionScript.

The idea: Draw a set of squares to represent the game field.

The development: Add this line to Main function:

public function Main() {
generateField();
}




then write generateField function this way:

private function generateField():void {
fieldArray = new Array();
fieldSprite=new Sprite();
addChild(fieldSprite);
fieldSprite.graphics.lineStyle(0,0x000000);
for (var i_uint=0; i<20; i++) {
fieldArray[i]=new Array();
for (var j_uint=0; j<10; j++) {
fieldArray[i][j]=0;
fieldSprite.graphics.beginFill(0x444444);
fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS);
fieldSprite.graphics.endFill();
}
}
}




Test the movie and you will see:

flash-game-development-creation-complete-tetris-game-img-0


The 20x10 game field has been rendered on the stage in a lighter gray. I could have used constants to define values like 20 and 10, but I am leaving it to you at the end of the article.

Let's see what happened:

fieldArray = new Array();
fieldSprite=new Sprite();
addChild(fieldSprite);




These lines just construct fieldArray array and fieldSprite DisplayObject, then add it to stage as you have already seen a million times.

fieldSprite.graphics.lineStyle(0,0x000000);




This line introduces a new world called Graphics class. This class contains a set of methods that will allow you to draw vector shapes on Sprites.

lineStyle method sets a line style that you will use for your drawings. It accepts a big list of arguments, but at the moment we'll focus on the first two of them.

The first argument is the thickness of the line, in points. I set it to 0 because I wanted it as thin as a hairline, but valid values are 0 to 255.

The second argument is the hexadecimal color value of the line, in this case black.

Hexadecimal uses sixteen distinct symbols to represent numbers from 0 to 15. Numbers from zero to nine are represented with 0-9 just like the decimal numeral system, while values from ten to fifteen are represented by letters A-F. That's the way it is used in most common paint software and in the web to represent colors.

You can create hexadecimal numbers by preceding them with 0x.

Also notice that lineStyle method, like all Graphics class methods, isn't applied directly on the DisplayObject itself but as a method of the graphics property.

for (var i_uint=0; i<20; i++) { ... }




The remaining lines are made by the classical couple of for loops initializing fieldArray array in the same way you already initialized all other array-based games, and drawing the 200 (20x10) rectangles that will form the game field.

fieldSprite.graphics.beginFill(0x444444);




beginFill method is similar to lineStyle as it sets the fill color that you will use for your drawings. It accepts two arguments, the color of the fill (a dark gray in this case) and the opacity (alpha). Since I did not specify the alpha, it takes the default value of 1 (full opacity).

fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS);




With a line and a fill style, we are ready to draw some squares with drawRect method, that draws a rectangle. The four arguments represent respectively the x and y position relative to the registration point of the parent DisplayObject (fieldSprite, that happens to be currently on 0,0 in this case), the width and the height of the rectangle. All the values are to be intended in pixels.

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime

fieldSprite.graphics.endFill();




endFill method applies a fill to everything you drew after you called beginFill method.

This way we are drawing a square with a TS pixels side for each for iteration. At the end of both loops, we'll have 200 squares on the stage, forming the game field.

Drawing a better game field background


Tetris background game fields are often represented as a checkerboard, so let's try to obtain the same result.

The idea: Once we defined two different colors, we will paint even squares with one color, and odd squares with the other color.

The development: We have to modify the way generateField function renders the background:

private function generateField():void {
var colors_Array=new Array("0x444444","0x555555");");
fieldArray = new Array();
var fieldSprite_Sprite=new Sprite();
addChild(fieldSprite);
fieldSprite.graphics.lineStyle(0,0x000000);
for (var i_uint=0; i<20; i++) {
fieldArray[i]=new Array();
for (var j_uint=0; j<10; j++) {
fieldArray[i][j]=0;
fieldSprite.graphics.beginFill(colors[(j%2+i%2)%2]);
fieldSprite.graphics.drawRect(TS*j,TS*i,TS,TS);
fieldSprite.graphics.endFill();
}
}
}




We can define an array of colors and play with modulo operator to fill the squares with alternate colors and make the game field look like a chessboard grid.

The core of the script lies in this line:

fieldSprite.graphics.beginFill(colors[(j%2+i%2)%2]);




that plays with modulo to draw a checkerboard.

Test the movie and you will see:

flash-game-development-creation-complete-tetris-game-img-1


Now the game field looks better.

Creating the tetrominoes


The concept behind the creation of representable tetrominoes is the hardest part of the making of this game. Unlike the previous games you made, such as Snake, that will feature actors of the same width and height (in Snake the head is the same size as the tail), in Tetris every tetromino has its own width and height. Moreover, every tetromino but the square one is not symmetrical, so its size is going to change when the player rotates it.

How can we manage a tile-based game with tiles of different width and height?

The idea: Since tetrominoes are made by four squares connected orthogonally (that is, forming a right angle), we can split tetrominoes into a set of tiles and include them into an array.

The easiest way is to include each tetromino into a 4x4 array, although most of them would fit in smaller arrays, it's good to have a standard array.

Something like this:

flash-game-development-creation-complete-tetris-game-img-2


Every tetromino has its own name based on the alphabet letter it reminds, and its own color, according to The Tetris Company (TTC), the company that currently owns the trademark of the game Tetris. Just for your information, TTC sues every Tetris clone whose name somehow is similar to "Tetris", so if you are going to create and market a Tetris clone, you should call it something like "Crazy Bricks" rather than "Tetriz".

Anyway, following the previous picture, from left-to-right and from top-to-bottom, the "official" names and colors for tetrominoes are:

  • I—color: cyan (0x00FFFF)
  • T—color: purple (0xAA00FF)
  • L—color: orange (0xFFA500)
  • J—color: blue (0x0000FF)
  • Z—color: red (0xFF0000)
  • S—color: green (0x00FF00)
  • O—color: yellow (0xFFFF00)


The development: First, add two new class level variables:

private const TS_uint=24;
private var fieldArray:Array;
private var fieldSprite:Sprite;
private var tetrominoes:Array = new Array();
private var colors_Array=new Array();




tetrominoes array is the four-dimensional array containing all tetrominoes information, while colors array will store their colors.

Now add a new function call to Main function:

public function Main() {
generateField();
initTetrominoes();
}




initTetrominoes function will initialize tetrominoes-related arrays.

private function initTetrominoes():void {
// I
tetrominoes[0]=[[[0,0,0,0],[1,1,1,1],[0,0,0,0],[0,0,0,0]],
[[0,1,0,0],[0,1,0,0],[0,1,0,0],[0,1,0,0]]];
colors[0]=0x00FFFF;
// T
tetrominoes[1]=[[[0,0,0,0],[1,1,1,0],[0,1,0,0],[0,0,0,0]],
[[0,1,0,0],[1,1,0,0],[0,1,0,0],[0,0,0,0]],
[[0,1,0,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]],
[[0,1,0,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]]];
colors[1]=0x767676;
// L
tetrominoes[2]=[[[0,0,0,0],[1,1,1,0],[1,0,0,0],[0,0,0,0]],
[[1,1,0,0],[0,1,0,0],[0,1,0,0],[0,0,0,0]],
[[0,0,1,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]],
[[0,1,0,0],[0,1,0,0],[0,1,1,0],[0,0,0,0]]];
colors[2]=0xFFA500;
// J
tetrominoes[3]=[[[1,0,0,0],[1,1,1,0],[0,0,0,0],[0,0,0,0]],
[[0,1,1,0],[0,1,0,0],[0,1,0,0],[0,0,0,0]],
[[0,0,0,0],[1,1,1,0],[0,0,1,0],[0,0,0,0]],
[[0,1,0,0],[0,1,0,0],[1,1,0,0],[0,0,0,0]]];
colors[3]=0x0000FF;
// Z
tetrominoes[4]=[[[0,0,0,0],[1,1,0,0],[0,1,1,0],[0,0,0,0]],
[[0,0,1,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]]];
colors[4]=0xFF0000;
// S
tetrominoes[5]=[[[0,0,0,0],[0,1,1,0],[1,1,0,0],[0,0,0,0]],
[[0,1,0,0],[0,1,1,0],[0,0,1,0],[0,0,0,0]]];
colors[5]=0x00FF00;
// O
tetrominoes[6]=[[[0,1,1,0],[0,1,1,0],[0,0,0,0],[0,0,0,0]]];
colors[6]=0xFFFF00;
}




colors array is easy to understand: it's just an array with the hexadecimal value of each tetromino color.

tetrominoes is a four-dimensional array. It's the first time you see such a complex array, but don't worry. It's no more difficult than the two-dimensional arrays you've been dealing with since the creation of Minesweeper. Tetrominoes are coded into the array this way:

  • tetrominoes[n] contains the arrays with all the information about the n-th tetromino. These arrays represent the various rotations, the four rows and the four columns.
  • tetrominoes[n][m] contains the arrays with all the information about the n-th tetromino in the m-th rotation. These arrays represent the four rows and the four columns.
  • tetrominoes[n][m][o] contains the array with the four elements of the n-th tetromino in the m-th rotation in the o-th row.
  • tetrominoes[n][m][o][p] is the p-th element of the array representing the o-th row in the m-th rotation of the n-th tetromino. Such element can be 0 if it's an empty space or 1 if it's part of the tetromino.


There isn't much more to explain as it's just a series of data entry. Let's add our first tetromino to the field.