|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
Note: This is an unedited contribution. If this article is inappropriate,
needs attention or copies someone else's work without reference then please
Report This Article
DownloadIntroductionI’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 in to details about the pattern but I would recommend reading about it. "Abstract Factory Design Pattern. You can read about the pattern here Starting offWhen 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 will figure out things the hard way. Just a shapeLets have a quick look the shape’s code. abstract class Shape
{
protected int turnState; // holds the current shape turn state shapes can rotate up to 4 times.
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 it's turnState.
*/
public abstract Point[] GetCoordinates(int top, int left);
}
As you can see shapes will be able to turn (90 degrees each time) and we can move the shape by retrieving it’s 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 squareclass 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 it’s top left coordinate is always at the same place. Shapes and their coordinatesthe square labeled one is our top left position which we keep track after.
Let me clarify the Lets say we’d like to move our square one row down what we will do is call the 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.
I’ve been babbling about coordinates for a while now lets see where they actually go. The Game’s board classThink 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:
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 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 Putting it all togetherSo how do things actually work? Lets quickly go over the game “Flow” The game asks the shape factory for a shape. More info about this class in the next section. 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. 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. Hard day at the factoryclass 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 shapes based on a random number. last wordsThe Game is missing some “key” features such as game boarders, letting the user know whats 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 shapes was surprisingly swift.
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||