13,096,798 members (92,997 online)
alternative version

#### Stats

33.3K views
26 bookmarked
Posted 6 Jul 2008

# Falling Blocks Game

, 6 Jul 2008
 Rate this:
Creating the game

## Introduction

I've been looking into some design patterns on DoFactory and as a good practice, I decided to write a Tetris game that uses the Factory pattern.

I'm not going to get into details about the pattern, but I would recommend reading about it.

"Abstract Factory Design Pattern.
Definition:
Provide an interface for creating families of related or dependent objects without specifying their concrete classes."

I assume you have all played the most famous falling blocks game 'Tetris' at some point in your life, so there’s no reason to explain the rules of the game.

## Starting Off

When I started writing the game, I didn't actually know where to start. As an objective, I decided not to look at any open source falling blocks code or any tutorial on the subject. I wanted to figure out things the hard way.

So I thought a good place to start would be the simplest shape there is - the cube - a four by four square. But just before that, we'll have to create an `abstract `class named `Shape `which all the actual shapes will inherit from.

## Just a Shape

Let's have a quick look at the `shape`’s code:

```abstract class Shape
{
// holds the current shape turn state shapes can rotate up to 4 times.
protected int turnState;
public int TurnState { get {return turnState;} set {turnState = value;}}

/*
* Returns the new cords of the shape after rotation.
*/
public abstract Point[] Turn(int top, int left);

/*
* Returns the current shape cords depends on the top left position
* of the shape and its turnState.
*/
public abstract Point[] GetCoordinates(int top, int left);
}```

As you can see, `shape`s will be able to turn (90 degrees each time) and we can move the `shape `by retrieving its coordinates for a desired top left position. We will keep track of the `shape`’s top left coordinate, this will keep things generalized.

So with the `Shape `class in place and the idea that every `shape `we'll create will inherit from it, let’s move on to our `square `class.

## Don't Be a Square

```class Square : Shape
{
public Square()
{
}

public override Point[] Turn(int top, int left)
{
return GetCoordinates(top, left);
}

public override Point[] GetCoordinates(int top, int left)
{
Point[] cords = new Point[4];
cords[0] = new Point(left, top);
cords[1] = new Point(left + 1, top);
cords[2] = new Point(left, top + 1);
cords[3] = new Point(left + 1, top + 1);
return cords;
}
} ```

Simple auh. The `square `doesn't need to turn so its top left coordinate is always at the same place.

## Shapes and their Coordinates

The `square `labelled 1 is our top left position which we keep track after.

Let me clarify the `GetCoordinates `method.

Let's say we'd like to move our square one row down. What we will do is call the `GetCoordinates `with Y increased by 1 and X remember we keep track after the top left coordinate. So by increasing Y by 1, we moved the `square `one row down:

`cords[0] = new Point(left, top) //is our new top left position `

Based on this point, we construct the rest of the `square`.

We still have to check if the move we just made is legit but will address this problem later on.
Once we understand this key concept of `shape`s representation and movement, creating new `shape`s is easy.

Rotating a `shape `is just a matter of figuring out how the `shape `should be laid out after rotation and where our top left coordinate should go, then all that's left is reconstructing the `shape `based on this new top left coordinate.

I wasn't so sure about what’s the right way to turn each `shape`, so I've come up with my own way.

I've been babbling about coordinates for a while now. Let's see where they actually go.

## The Game’s Board Class

Think of the game as a two dimensional Boolean grid that has width and height, a filled space will be marked as `true`, free space will be set to `false`.

The board class manages the game’s board by:

• Checking if it’s possible to reposition a given shape
• Redrawing the shape to the screen
• Updating the boolean values of the game board matrix
• Checking if any rows have been filled

It seems logical to put all this responsibility in one place. There’s much to this class so I'll point out only few things that I find interesting.

One question that came up is how do we know if a certain shape’s move (right, left, down, rotate) is possible?

Sure we can implement a complex check for each shape, but this would take too long. Fortunately there's a quicker way to do this.

Let’s have a look at the board’s class `Move `method:

```public bool Move(Point[] currentPos, Point[] desiredPos)
{
if (!LegitMove(currentPos, desiredPos))
return false;

// Remove shape from the board
Pen pen = new Pen(backgroundColor, 3);
DrawShape(currentPos, pen);

// Redraw
RePosition(desiredPos);

pen = new Pen(Color.Blue, 3);
DrawShape(desiredPos, pen);

return true;
}
```

The method gets the current shape position coordinates and the desired coordinates (where the shape wishes to move).

What we do within the `LegitMove `method is create a copy of the game’s board and “Cut out” the current shape from it so it won't take any space, then we try to paste the shape to its new position. If we succeed doing so, the move is legit and we overwrite the game’s board with the copy we've made. Otherwise we can't move the shape to its new location and return `false `indicating no changes have been made to the original game’s board.

This gives us a simple mechanism for checking all imaginable `shape`s moves as long as we have a way to get the current `shape`s position (its coordinates on the board) and its new desired position.

## Putting It All Together

So how do things actually work? Let's quickly go over the game “Flow”.

The game asks the `shape `factory for a `shape`. More information about this class in the next section.
As far as we are concerned, we don't care what the actual `shape `is. All we know is that we've got a `shape `and we can interact with it.

Next we try to position the `shape `on the board at the top middle. If we failed to do that, we assume the board is filled up to the top and that means the game is over.

Otherwise we set a timer that will move our `shape `down one row within each tick.
If the `shape `moved down one row successfully, we do nothing.

Otherwise if the `shape `couldn't move one row down, then that's because it hit some other `shape `or it reached the game’s bottom board. We will have to check if the player had managed to fill a whole row(s), so we perform the check and update the board if needed (Clear filled rows, reposition rows above the cleared rows).

That's about it for the current `shape`. So get a new `shape `from our factory and repeat.

During this whole process, the user can manipulate the current `shape `by rotating, moving left, right and down, and for each “reposition”, we check if the move is possible.

## Hard Day at the Factory

```class ShapesFactory
{
Random rand;
enum shapes { Square, Stick, L, MirroredL, Plus, Z, MirroredZ };

public ShapesFactory()
{
rand = new Random();
}

public Shape GetShape()
{
int shape = rand.Next(7);
switch (shape)
{
case (int)shapes.Square:
return new Square();
break;

case (int)shapes.Stick:
return new Stick();
break;

.
.
.

case (int)shapes.MirroredZ:
return new MirroredZ();
break;

default:
return new Square();
}
}```

This class is responsible for creating new `shape`s based on a random number.
The factory has its products (L, cube, Z, etc.) and when the game requires a `shape`, the factory delivers.

## Last Words

The game is missing some “key” features such as game boarders, letting the user know what the next `shape `is going to be, displayed and keep score.

But the main core of the game is there and that was my actual goal. Also the graphics aren't that good, but I'm not a designer.

I enjoyed writing this game, it took me a while to figure out how things should work, but once I got the check mechanism in place and the `Shape `class `abstract `methods, adding new `shape`s was surprisingly swift.

That about wraps it. I hope I've pointed out some key view points on how this game works. In case you've got any comments or questions, please feel free to write to me.

## History

• 6th July, 2008: Initial post

## Share

 Architect AVG Israel
No Biography provided

## You may also be interested in...

 First Prev Next
 haha - mirroredL, mirroredZ? max2929714-Feb-09 12:09 max29297 14-Feb-09 12:09
 Good but not excellent alonk29-Jul-08 6:18 alonk 29-Jul-08 6:18
 New Development mikemac43447-Jul-08 16:29 mikemac4344 7-Jul-08 16:29
 Re: New Development Lipman Roi7-Jul-08 19:56 Lipman Roi 7-Jul-08 19:56
 Re: New Development alonk29-Jul-08 5:53 alonk 29-Jul-08 5:53
 Re: New Development Lipman Roi29-Jul-08 5:59 Lipman Roi 29-Jul-08 5:59
 Re: New Development alonk29-Jul-08 6:26 alonk 29-Jul-08 6:26
 Interesting Thomas Stockwell7-Jul-08 3:11 Thomas Stockwell 7-Jul-08 3:11
 Last Visit: 31-Dec-99 18:00     Last Update: 23-Aug-17 10:06 Refresh 1