Save up to 80 % on our C and C++ e-learning courses. Only this week!

# Lesson 8 - Tetris in MonoGame: Game Board

In the previous lesson, Tetris in MonoGame: Block Generator, we implemented the block generator for our Tetris game.

Today we're going to create another game object - the game board.

## Game Board

We already have the level component, which is the main game scene, we got the random block generator, and the falling block object. But we're missing the game board.

It's an object that'll contain a two-dimensional array of the fallen blocks, a method that checks whether the falling block collides with the game board, a method that adds the fallen block into the array, a method that removes complete rows, and, of course, a method that renders all the tiles on the game board.

Let's add a `GameBoard` class to the project, make it `public` and add the necessary `using` statements:

```using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;```

### Fields

As with the block, we'll add a tiles array here:

`private int[,] tiles;`

Next, we'll add the width and the height of the game board (measured in tiles):

```private int width;
private int height;```

The last field will be the game board's rendering position in the level background:

`private Vector2 position;`

### Clearing Tiles

Let's add a simple method that'll clear the game board by initializing the tiles array:

```public void Clear()
{
tiles = new int[width, height];
}```

### Constructor

Now we'll add a constructor, which will take the game board dimensions and position as parameters, and will initialize the game board instance:

```public GameBoard(int width, int height, Vector2 position)
{
this.width = width;
this.height = height;
this.position = position;
Clear();
}```

### Placing a New Block

Another method will be `InsertBlock()`, which will return the spawn coordinates of a new block we pass as a parameter. This position will make the block appear at the center of the game board's top edge.

```public Vector2 InsertBlock(Block block)
{
return new Vector2(((int)width / 2) - 1, 0);
}```

Nothing too complicated, we just divide the game board width by two to get the center. The method should consider various block shapes we pass to it, and sometimes set the `Y` coordinate to `-1` because the block's first row may be empty. But for the sake of simplicity we'll omit that for now.

### Merging the Block and the Board

Now let's implement the `Merge()` method, which will take a block as a parameter and add its tiles to the ones that are already fallen and became the fixed part of the game board. We'll loop through all the block's tiles, and in case any of the tiles isn't out of the game board's top edge (this can happen when the game is over, so we have to check it), we'll put it at its respective position among the game board fallen tiles.

```public void Merge(Block block)
{
// looping through all block tiles
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++)
{
// getting tile coordinates in the game board
int x = Convert.ToInt32(i + block.position.X);
int y = Convert.ToInt32((j + block.position.Y));
// the tile isn't empty and isn't out of the game board
if ((block.Tiles[i, j] > 0) && (y >= 0))
tiles[x, y] = block.Tiles[i, j];
}
}```

A little awkward here is that we have to convert the real vector components to integers. But generally, using vectors is still a good choice.

### Block Collision

Another important method that needs to be implemented is the `Collision()` method, which will return `true` if the block collides with any of the game board tiles. The method will take the block and its position as parameters. Although the block itself already contains its position, it'll come in handy to pass the position separately, because we're going to ask: "Would the block collide if it were at the position...".

Initially, we'll assume that there's no collision. So let's add a `collision` variable and set it to `false`. Then, as always, we'll loop through all the tiles:

```public bool Collision(Block block, Vector2 position)
{
bool block = false;
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++)```

Now we have to deal with a rather complex condition, which we'll split into more parts to describe it. If the block tile isn't empty:

`if ((block.Tiles[i, j] > 0) &&`

and its position is out of the game board:

`((j + position.Y >= height) || (i + position.X < 0) || (i + position.X >= width) ||`

or it overlaps with any game board tile:

`(tiles[Convert.ToInt32(i + position.X), Convert.ToInt32(j + position.Y)] > 0)))`

then a collision occurred:

`collision = true;`

Finally, we'll return the result. The complete method code is as follows:

```public bool Collision(Block block, Vector2 position)
{
// we'll assume there is no collision
bool collision = false;
// looping through all block tiles
for (int j = 0; j < 4; j++)
for (int i = 0; i < 4; i++)
// If the block tile isn't empty and
if ((block.Tiles[i, j] > 0) &&
// its position is out of the game board or
((j + position.Y >= height) || (i + position.X < 0) || (i + position.X >= width) ||
// it overlaps any game board tile
(tiles[Convert.ToInt32(i + position.X), Convert.ToInt32(j + position.Y)] > 0)))
// then a collision occurred
collision = true;
return collision;
}```

All we need now is removing complete rows and rendering.

### Removing Rows

The `RemoveRows()` method will remove all complete tile rows in the game board, and of course move down the tiles that are above the row. The return value will be of the `int` type and it'll indicate how many rows have been removed. This will be important to calculate the score later.

First we'll create a counter of removed rows and set it to `0`. Furthermore, we'll loop through all game board rows. Finally, we'll return the counter value:

```public int RemoveRows()
{
// complete rows check
int count = 0;
for (int count = 0; count < height; count++)
{

}
return count;```

In each loop iteration, we have to find out whether the row is complete. At first we'll assume that the current row is complete. Then we'll go through each of the row tiles, and if we find one that is empty, we'll conclude that the row isn't complete:

```// let's assume the row is complete
bool complete = true;
// if there is any tile empty, it's not complete
for (int i = 0; i <= (width - 1); i++)
if (tiles[i, row] == 0)
complete = false;```

In the case there's a complete row, all above rows need to be moved down by one tile and the complete rows counter has to be incremented. We'll start from the bottom:

```// complete row removing
if (complete)
{
// moving down the above rows
for (int j = (row - 1); j > 0; j--)
for (int i = 0; i < width; i++)
tiles[i, j + 1] = tiles[i, j];
count++;
}```

Just to make sure, here's the whole method code:

```public int RemoveRows()
{
// complete rows check
int count = 0;
for (int row = 0; row < height; row++)
{
// let's assume the row is complete
bool complete = true;
// if there is any tile empty, it's not complete
for (int i = 0; i <= (width - 1); i++)
if (tiles[i, row] == 0)
complete = false;
// complete row removing
if (complete)
{
// moving down the above rows
for (int j = (row - 1); j > 0; j--)
for (int i = 0; i < width; i++)
tiles[i, j + 1] = tiles[i, j];
count++;
}
}
return count;
}```

### Rendering the Game Board

Let's add the rendering method. There's nothing complicated about it, the game board is rendered exactly the same as the block:

```public void Draw(SpriteBatch spriteBatch, Texture2D[] sprites)
{
for (int j = 0; j <= (height - 1); j++)
for (int i = 0; i <= (width - 1); i++)
if (tiles[i, j] != 0)
spriteBatch.Draw(sprites[tiles[i, j] - 1], new Vector2(position.X + i * sprites[0].Width, position.Y + j * sprites[0].Height), Color.White);
}```

The `GameBoard` class is now complete.

In the next lesson, Tetris in MonoGame: Functional Game Core, we'll make the game functional and try to play it

Application includes source codes

Article has been written for you by David Capka