Creating your own Tetris game using VB.NET

Introduction

Seeing the fact that the game Tetris has turned 25, recently, I thought it'd be nice to create my own version of the popular game.  OK, not entirely different, the game still needs to have all the necessary shapes, called tetrominoes, but we'll get to the complicated things a bit later.  For now, all you need to know is that we are going to create our own Tetris game, throughout this article series.

Logic / Explanation

Tetris makes use of tetrominoes. A tetromino, also spelled tetramino or tetrimino, is a geometric shape composed of four squares, connected orthogonally. This is a particular type of polyomino, just like dominoes and pentominoes. Sometimes the term is generalized to apply to configurations of four orthogonally connected cubes.  There are seven possible shapes :

Shape Picture
I
O
T
L
J
S
Z

Planning this project actually took some time.  Obviously you cannot just jump in and create the project and it will be perfect.  you always have to think logically.  As it is, we can break down this game into 4 logical parts.

Part 1

The design; in other words the form's design, the user interface - what the user will see, and do.

Part 2

This part is probably the most important piece of the puzzle of all.  Without this piece, there will be no game at all.  I am talking about the Grid.  The grid is a set of invisible blocks.  Everything displayed, will be in the grid.  having a grid will help us in determining where precisely each shape ( and further each block of each shape ) is.  Having a grid further simplify our shapes' navigation.

Part 3

A Display object. No, it is not the graphics object with which we draw.  It is a separate object which basically assists in double buffering.  This means that there will be no glitches or breaks in animation during the game.  How this works is that it creates a separate graphics object, and copies the current objects to an from it, but more on that in the next instalment of this series.

Part 4

Shapes.  The shapes must be handled separately.  The physical drawing of the shapes, plus the movement of them.  This will be explained later in the article series.

We will cover only the first 2 logical parts of this game, in this article. The design is not much work.  The real work came in with creating the Grid.  With the Grid, we have to make sure we always know where is which object; we also need to make sure that all colours are placed correctly, and most importantly, we have to determine the empty spaces and the used spaces - we cannot place the shapes properly then. Let us start with the design of our form.

Creating your own Tetris game using VB.NET

Design

Start a new project and add the following to the form

Object Property Setting
Form Name frmTet
  Size 211, 363
  Text Tetrimino
Panel Name pnlTetGame
  Backcolor Black
  Size 161, 301

As you can see, we start with a very basic layout.  Honestly, do not expect much from this project we're creating, as this is only the beginning, and we are only actually creating the Grid.  Let's continue with the code.

Coding

Open frmTet in Code View, and add the following sub procedure:

    ''' <summary>
    ''' Displays The Letters HTG When Loaded
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Splash()
        Dim gStart As Graphics = pnlTetGame.CreateGraphics() 'Enable Drawing Onto Panel
        gStart.Clear(Color.Black) 'Clear If There Was Something

        'Create H Shape
        gStart.FillRectangle(New SolidBrush(Color.Red), 25, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 25, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 25, 105, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 25, 105, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 25, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 25, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 25, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 25, 115, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 25, 120, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 25, 120, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 30, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 30, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 35, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 35, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 40, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 40, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 40, 105, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 40, 105, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 40, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 40, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 40, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 40, 115, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Red), 40, 120, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 40, 120, 5, 5)

        'Create T Shape
        gStart.FillRectangle(New SolidBrush(Color.Green), 55, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 55, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 60, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 60, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 65, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 65, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 60, 105, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 60, 105, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 60, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 60, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 60, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 60, 115, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Green), 60, 120, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 60, 120, 5, 5)

        'Create G Shape
        gStart.FillRectangle(New SolidBrush(Color.Blue), 85, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 85, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 90, 100, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 90, 100, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 80, 105, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 80, 105, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 80, 110, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 80, 110, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 80, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 80, 115, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 85, 120, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 85, 120, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 90, 120, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 90, 120, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 95, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 95, 115, 5, 5)

        gStart.FillRectangle(New SolidBrush(Color.Blue), 100, 115, 5, 5)
        gStart.DrawRectangle(New Pen(Color.White, 1), 100, 115, 5, 5)

    End Sub

    Private Sub frmTet_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
        Splash() 'Draw
    End Sub

This creates the initial "splash screen" inside the main panel.  The letters HTG gets printed in blocks, as shown in the following figure:

[HTG_Splash.jpg]
Figure 1.1

Creating your own Tetris game using VB.NET

Let us now add the Grid class

Let us now add the Grid class, Select Add Class form the Project menu Name the class clsTetGrid, and add the following:

    Private arrGrids As Rectangle()() 'Each Block

    Private arrGridBrushes As SolidBrush()() 'Each Shape's grid
    Private arrColours() As SolidBrush 'Each Shape's Colour

Here we just create the modular variables to be used throughout clsTetGrid. We create the Grid, which occupies the whole game area, and where all the various shapes will be drawn onto.  Then, we create a brush along with a colour for each block. Now add the constructor :

    ''' <summary>
    ''' Initialises The Grid
    ''' </summary>
    ''' <param name="intGridRows">Each Row</param>
    ''' <param name="intGridCols">Each Column</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal intGridRows As Integer, ByVal intGridCols As Integer)

        arrGrids = New Rectangle(intGridRows)() {} 'Create Row(s)
        arrGridBrushes = New SolidBrush(intGridRows)() {} 'Create Grid For Each Row
        arrColours = New SolidBrush(7) {} 'Colours Of Shapes

        Dim i As Integer 'Counter For Loop

        For i = 0 To intGridRows - 1 'Loop Through Each Row

            arrGrids(i) = New Rectangle(intGridCols) {} 'Create Each Column Block
            arrGridBrushes(i) = New SolidBrush(intGridCols) {} 'Create Each Column Border

        Next i

        'Colours For Shapes
        arrColours(0) = New SolidBrush(Color.Blue)
        arrColours(1) = New SolidBrush(Color.Red)
        arrColours(2) = New SolidBrush(Color.Green)
        arrColours(3) = New SolidBrush(Color.Yellow)
        arrColours(4) = New SolidBrush(Color.Brown)

        arrColours(5) = New SolidBrush(Color.Orange)
        arrColours(6) = New SolidBrush(Color.Purple)

    End Sub

The grid blocks physically get created here with the For Loop, how many there will be will depend on the number of Columns and rows inputted.  The colours of our 7 shapes also get initialised here.  More on Shapes later.

Add the following Functions :

    ''' <summary>
    ''' Get Whole Grid Object Array
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GetGrid() As Rectangle()()
        Return arrGrids
    End Function

    Public Function GetGridBrushes() As SolidBrush()()
        Return arrGridBrushes
    End Function

    ''' <summary>
    ''' Get All Colours Associated With Grid Object Array
    ''' </summary>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function GetColours() As SolidBrush()
        Return arrColours
    End Function

Add the following  :

   ''' <summary>
    ''' Determine If block Is Unoccupied
    ''' </summary>
    ''' <param name="intRowNo">Specify Row</param>
    ''' <param name="intColNo">Specify Column</param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function IsLocEmpty(ByVal intRowNo As Integer, ByVal intColNo As Integer) As Boolean

        If arrGrids(intRowNo)(intColNo).IsEmpty Then
            Return True 'If Location is Empty
        Else
            Return False 'If Not
        End If

    End Function

    ''' <summary>
    ''' Get The Top Row Of The Main Game Panel Grid
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub FirstRow()

        'Top Row Is Equal To The UpperBound Of arrGrids
        arrGrids(0) = New Rectangle(arrGrids(1).Length) {}

    End Sub

The function IsLocEmpty just determines if the current block is empty, or already occupied.  The FirstRow sub, just gets and sets the first row of the grid. Add the following:

    ''' <summary>
    ''' When The Shape Moves Down, Row By Row
    ''' </summary>
    ''' <param name="intRowNo">Specify Row</param>
    ''' <param name="intColNo">Specify Column</param>
    ''' <remarks></remarks>
    Public Sub DropDown(ByVal intRowNo As Integer, ByVal intColNo As Integer)

        If Not IsLocEmpty(intRowNo - 1, intColNo) Then 'Check If Next Row Is Empty

            'Set Current Location Equal To The Same Location Horizontally, But
            'Next Row ( Vertically )
            'Size Is 10
            arrGrids(intRowNo)(intColNo) = New Rectangle(arrGrids((intRowNo - 1))(intColNo).X, arrGrids((intRowNo - 1))(intColNo).Y + 10, 10, 10)

            'Make Sure Gridlines Move Too
            arrGridBrushes(intRowNo)(intColNo) = arrGridBrushes((intRowNo - 1))(intColNo)

        Else 'Next Row Is Not Empty
            arrGrids(intRowNo)(intColNo) = arrGrids((intRowNo - 1))(intColNo)
        End If

    End Sub

    ''' <summary>
    ''' Make Sure Gridlines And Colours Follow Shapes
    ''' </summary>
    ''' <param name="intRowNo">Current Row</param>
    ''' <param name="intColNo">Current Column</param>
    ''' <param name="rctCell">Intersection Of Current Row And Current Column</param>
    ''' <param name="intShapeType">Shape Index</param>
    ''' <remarks></remarks>
    Public Sub SetLoc(ByVal intRowNo As Integer, ByVal intColNo As Integer, ByVal rctCell As Rectangle, ByVal intShapeType As Integer)

        arrGrids(intRowNo)(intColNo) = rctCell 'Identify Current Cell ( Block )

        SetColourLoc(intRowNo, intColNo, intShapeType) 'Move Colour To Specified Cell

    End Sub
    ''' <summary>
    ''' Move Colour To Associated Row & Col
    ''' </summary>
    ''' <param name="intRowNo">Current Row</param>
    ''' <param name="intColNo">Current Col</param>
    ''' <param name="intShapeType">Shape Index</param>
    ''' <remarks></remarks>
    Public Sub SetColourLoc(ByVal intRowNo As Integer, ByVal intColNo As Integer, ByVal intShapeType As Integer)

        'Set Colour Index To Grid Index
        arrGridBrushes(intRowNo)(intColNo) = arrColours((intShapeType - 1))

    End Sub    

These last 3 procedures of our Grid class work with the current position of the shape blocks.  As the shape blocks move down, the colour must follow it.  These 2 procedures don't move the shapes, you must understand that.  They just keep track of the current shape and its position in the grid, so that the grid can be updated and we can see where is which shape as we play.

This covers the Grid class.  The next part we will cover is the Displaying of all objects, and smooth animation.

Conclusion

Well, short and sweet; for now at least.  Unfortunately this article has ended quite abruptly, or blunt, for me as well.  I figure that this would be a good place to stop, as the whole grid is covered.  From here on, we will create the shapes, and the physical display of the game, to ensure that we get smooth animation effects.  There is still a lot of work, so stick around for the next installment in this series.  Until then, happy coding!



About the Author

Hannes du Preez

Hannes du Preez is a Microsoft MVP for Visual Basic. He is a trainer at a South African-based company. He is the co-founder of hmsmp.co.za, a community for South African developers.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Live Event Date: October 29, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT It's well understood how critical version control is for code. However, its importance to DevOps isn't always recognized. The 2014 DevOps Survey of Practice shows that one of the key predictors of DevOps success is putting all production environment artifacts into version control. In this eSeminar, Gene Kim will discuss these survey findings and will share woeful tales of artifact management gone wrong! Gene will also share examples of how …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds