Creating your own Tetris game with VB.NET

Introduction

Playing games not set up correctly can be really annoying and frustrating.  I'm not a huge gamer, but every now and then I'd like to see if I can beat my score on Spider Solitaire.  Getting into the game market now, because of my daughter, I have come to realise how many games there are out there, which were created quickly and haphazardly.  Call me stupid, but I believe the most most important part of game design ( doesn't matter what game it is ), is the displaying and smoothness of of all objects.  It looks very unprofessional when, upon a certain movement the game flickers or the moved object simply doesn't move quick enough.  It is especially bad when the moved object(s) still leave traces of their original location after the move.  All these reasons spurred me on, to ensure that I create a proper display class, so that issues like the aforementioned issues never ever arise.

Logic / Explanation

You may be thinking: "How can these issues be fixed, if possible even?" Two words : Double Buffering. What we will do in this article is create a class that can handle all the image buffering.  Once we have this class created, we create objects from it for our Preview window, our Splash window as well as our physical game window.  In Part 1 of this series we have created the Grid for all the Tetris blocks, and designed the basic user interface.  Now, we will take it a tiny step further, by adding more controls and setting default values for all the labels as well as beginning with the actual game's logic.  Let us start with the design

Design

If you haven't completed the first part's exercise, I suggest you do so now. If you have completed it you will know that the main interface was just a black panel.  We will expand on that now.  Open part 1, and add the following controls with their associated Properties :

Control Property Setting
Label Text Score
Label Text Level
label Text Rows
Label Name lblTetScore
  Text Empty
  BorderStyle Fixed3D
Label Name lblTetLevel
  Text Empty
  BorderStyle Fixed3D
Label Name lblTetRows
  Text Empty
  BorderStyle Fixed3D
Label Text Preview
Panel Name pnlTetPreview
  BackColor Black
  Size 115, 67
Panel Name pnlMovement
Timer Name tmrTet

Resize your main form where necessary. Not all of the controls added now are 100% essential at this stage, but it is good to have the User Interface up to this point, so that you can also get a larger picture of what will happen in this game, and what is to be expected.

Your design should more or less resemble the following picture

Figure 1.1

Creating your own Tetris game with VB.NET

Coding

The coding is actually quite straight forward.  First we would have to create the Display class, and then implement it on our form.  Ready?  Let's go!

Add a new class to your existing project and give it name of clsTetDisplay.

Add the following variable declarations to clsTetDisplay :

    Protected g As Graphics = Nothing 'Graphics Object To Draw With
    Protected InMemoryGraphics As Graphics = Nothing 'Temporary Graphics PlaceHolder

    Protected InMemoryImage As Image = Nothing 'Temporary Image PlaceHolder

    Public ScreenX As Integer = 0 'Starting X of Panel
    Public ScreenY As Integer = 0 'Starting Y Of Panel
    Public ScreenWidth As Integer = 0 'Width Of Panel
    Public ScreenHeight As Integer = 0 'Height Of Panel

These variables create the buffered image, which gets saved into memory. The InMemoryGraphics and InMemoryimage will store the "Saved" picture for later use
The Various Screen... variables just set up the picture according to a certain height and width, and horizontal and vertical starting points

Next, add the constructor

    ''' 
    ''' Initializes New Display Graphic
    ''' 
    ''' Panel To Use
    ''' Rectangle to Use
    ''' 
    Public Sub New(ByVal p As Panel, ByVal r As Rectangle)

        g = p.CreateGraphics() 'Start Drawing

        ScreenX = r.X 'Start Where r Starts, Horizontally
        ScreenY = r.Y 'Start Where r Starts, Vertically

        ScreenWidth = r.Width 'Same Width As r
        ScreenHeight = r.Height 'Same Height As r

        InMemoryImage = New Bitmap(ScreenWidth, ScreenHeight) 'Create Image Size
        InMemoryGraphics = Graphics.FromImage(InMemoryImage) 'Create Image

    End Sub

In our constructor, we make use of 2 arguments: p and r ( not very descriptive names, I agree ). p is the physical panel on which we want to draw onto. r is a Rectangle ( sized the same as the panel ).  This rectangle will contain our in memory picture. Inside the constructor, we start the drawing operation, determines where our in memory graphic should start and its dimensions, and draw the picture into memory

Add the next Function:

    ''' 
    ''' Returns Temp Image
    ''' 
    ''' 
    ''' 
    Public Function GetGraphics() As Graphics

        Return InMemoryGraphics 'Get In Memory Graphic

    End Function

GetGraphics gets the in memory graphic ( the buffered image ), because it is a function we can use this picture where we want

The next function:

    ''' 
    ''' Determine Existance Of In Memory Graphic
    ''' 
    ''' 
    ''' 
    Public Function ValidGraphic() As Boolean

        If Not (g Is Nothing) And Not (InMemoryGraphics Is Nothing) Then
            Return True 'If There Is A Graphic In Memory 
        Else
            Return False 'If Not
        End If

    End Function

Determines if there is indeed a picture stored in memory, and returns either True or False based on the result of the test

ClearScreen:

    ''' 
    ''' Erase Game Screen
    ''' 
    ''' 
    Public Sub ClearScreen()

        'If No Valid Graphic, Do Nothing
        If Not ValidGraphic() Then
            Return
        End If

        'Create A Solid Black Brush
        Dim ClearBrush As New SolidBrush(Color.Black)

        'Fill The Rectangle With The Black Colour, Causing The Clearance of The Images
        InMemoryGraphics.FillRectangle(ClearBrush, 0, 0, ScreenWidth, ScreenHeight)

    End Sub

This sub simply clears the image's previous location.  We have to clear the previous locations of the images as they drop down row by row.  If we do not clear the previous location, we will end up with columns of filled rectangles depending on the shape's dimensions

The last Sub:

    ''' 
    '''Ensures Smooth Animation, As Image Is Already Buffered 
    ''' 
    ''' 
    Public Sub BufferImage()

        g.DrawImage(InMemoryImage, ScreenX, ScreenY)

    End Sub

The BufferImage sub ensures smooth animation; because the image is already drawn into memory, when displaying it will look flawless.

Creating your own Tetris game with VB.NET

frmTet

Add the following variable declarations to frmTet:

    Private scrGame As clsTetDisplay 'Declare Physical Game Object
    Private scrSplash As clsTetDisplay 'Declare Object To Be Shown On Preview Block
    Private scrPreview As clsTetDisplay 'Declare "HTG" Display Object

    Private rctScreen As Rectangle 'Screen To Draw Onto

    Private intGameSpeed As Integer 'How Fast Is The Game?
    Private intDropRate As Integer 'How Fast Should It Drop?
    Private intLevel As Integer 'User's Level
    Private intLevelRows As Integer 'Number Of Rows - Current Level
    Private intTotalRows As Integer 'Total Rows
    Private GameWidth As Integer 'Width Of Game Screen
    Private GameHeight As Integer 'Height Of Game Screen
    Private intNoOfRows As Integer 'Number Of Rows
    Private intNoOfCols As Integer 'Number Of Columns

    Private lngScore As Long 'User's Score

    Private blnDropped As Boolean = False 'Has There Been An Object Dropped?
    Private blnGameOver As Boolean 'Is The Game Over?

The first 3 variables creates our Display objects: one for the actual game panel, one for the Preview panel, and one for the Splash Screen text. rctScreen is the particular "screen" to draw onto, and it can be either the Preview panel or the game panel. The rest of the variables will be used during the playing of the game.  How man rows have been completed? What is the current score? And so on.

Add the next Sub procedure:

    ''' 
    ''' Set Up Of Game And Default Values
    ''' 
    ''' 
    Private Sub SetUp()

        intGameSpeed = 100 'Game Speed = 100 Milliseconds
        intDropRate = 5 'Dropping Speed = 5 Milliseconds
        lngScore = 0 'Initialise Score
        intLevel = 1 'Initialise Level
        intLevelRows = 0 'Initialise Level Rows
        intTotalRows = 0 'Initialise Total Rows
        blnGameOver = True 'Initialise Game Over State
        blnDropped = False 'Initialise Dropped State

        lblTetScore.Text = lngScore.ToString() 'Show Score In Appropriate Label
        lblTetLevel.Text = intLevel.ToString() 'Show Level In Appropriate Label
        lblTetRows.Text = intTotalRows.ToString() 'Show Total Rows In Appropriate Label


        rctScreen = New Rectangle(0, 0, pnlTetGame.Width, pnlTetGame.Height) ' Create Main Game Window


        GameWidth = rctScreen.Width 'Set Width
        GameHeight = rctScreen.Height 'Set Height

        scrGame = New clsTetDisplay(pnlTetGame, rctScreen) 'Initialise Game Object

        rctScreen = New Rectangle(0, 0, pnlTetPreview.Width, pnlTetPreview.Height) 'Initialise & Size Preview Window
        scrPreview = New clsTetDisplay(pnlTetPreview, rctScreen)

        rctScreen = New Rectangle(0, 0, pnlTetGame.Width, pnlTetGame.Height) 'Start Splash Screen Window
        scrSplash = New clsTetDisplay(pnlTetGame, rctScreen)


        intNoOfRows = (pnlTetGame.Height - 1) / 10 'Create Game Grid & Creating 10 x 10 Sized Blocks
        intNoOfCols = (pnlTetGame.Width - 1) / 10

        grdGame = New clsTetGrid(intNoOfRows, intNoOfCols) 'Create Grid
    End Sub

This sub, as its name implies sets up our game.  Whenever we call this, everythings gets reverted back to their default values.  The actual initialising of the Display objects also happen inside here, now we are ready to start with the game's logic.

Conclusion

Well, that's it; for now.  We have now finished all the upfront work needed to have a decent distributable / marketable game.  With the next installment of this article series, we will create the actual Tetris blocks and make them move and work as it should.  I sincerely hope you have benefited from this article, and this series so far, and please make sure to join me for the third part soon!

Have fun!



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 …

  • On-demand Event Event Date: October 23, 2014 Despite the current "virtualize everything" mentality, there are advantages to utilizing physical hardware for certain tasks. This is especially true for backups. In many cases, it is clearly in an organization's best interest to make use of physical, purpose-built backup appliances rather than relying on virtual backup software (VBA - Virtual Backup Appliances). Join us for this webcast to learn why physical appliances are preferable to virtual backup appliances, …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds