The VB WinForm version of the typing tutor game

In this post, Create your own typing tutor! is code to create a game for learning the letters of the keyboard by typing the letters that fly across the screen. As times goes by, they fly faster.

Below is a VB version of the game. Can you score higher than 3000?

Start Visual Studio (most versions will work). Choose File->New->Project->VB->Windows Forms Application. Paste in the code below.

In this link: How to: Give Your Control a Transparent Background , it says:

Windows Forms controls do not support true transparency. The background of a transparent Windows Forms control is painted by its parent

This can be seen when running the code: some letters which are on top of other letters don't paint right

The title of this post says “WinForm”. What will a WPF version look like?

Public Class Form1

    Dim WithEvents oTimer As Timer

    Dim nScore As Integer = 0

    Dim nTicks = 0

    Dim nHighScore As Integer = 0

    Dim nInterval = 100

    Const MAXLETS = 10

    Dim aLets(MAXLETS - 1) As MyLabel

    Dim nMaxSecs = 30

    Declare Function Beep Lib "kernel32" (ByVal nFreq As Int32, ByVal nDura As Int32) As Integer

    Dim oRand As New Random

    Dim sHighScoreFile = My.Application.Info.DirectoryPath + IO.Path.DirectorySeparatorChar + "letters.txt"

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Me.Left = 200

        Me.Width = 600

        Me.Height = 300

        Me.BackColor = Color.White

        ' Me.BackgroundImage = New Bitmap("d:\kids.jpg")

        For i = 0 To MAXLETS - 1

            Me.aLets(i) = New MyLabel

            Me.Controls.Add(Me.aLets(i))

        Next

        If My.Computer.FileSystem.FileExists(sHighScoreFile) Then

            Me.nHighScore = Int(Val(My.Computer.FileSystem.ReadAllText(sHighScoreFile)))

        End If

        oTimer = New Timer

        oTimer.Interval = Me.nInterval

        oTimer.Start()

    End Sub

    Private Sub Form1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress

        If e.KeyChar = Chr(27) Then 'escape key

            Me.Close()

  Else

            Dim oGotOne As MyLabel = Nothing

            For i = 0 To MAXLETS - 1

                With Me.aLets(i)

                    If .Visible And .Text = e.KeyChar.ToString.ToUpper Then

                        If oGotOne Is Nothing OrElse .Left < oGotOne.Left Then ' get leftmost

                            oGotOne = Me.aLets(i)

                        End If

                    End If

                End With

            Next

            If oGotOne Is Nothing Then

                Me.BadOne(50) ' no match: penalty

            Else

                oGotOne.Visible = 0

                Me.nScore += oGotOne.Left / 10 ' higher score for rightmost

            End If

        End If

    End Sub

    Private Sub oTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles oTimer.Tick

        Me.nTicks += 1

        Dim nSecs = Me.nTicks * Me.nInterval / 1000

        If nSecs > Me.nMaxSecs Then ' out of time?

            oTimer.Stop()

            For i = 0 To MAXLETS - 1

               Me.aLets(i).Visible = 0 ' hide all the letters

            Next

            If Me.nHighScore < Me.nScore Then

                MsgBox("New High Score: " + Me.nScore.ToString + _

                       "! Old = " + Me.nHighScore.ToString, MsgBoxStyle.Exclamation)

                Me.nHighScore = Me.nScore

                My.Computer.FileSystem.WriteAllText(Me.sHighScoreFile, Me.nHighScore.ToString, 0)

            Else

                MsgBox("Your Score: " + Me.nScore.ToString + " High Score = " + Me.nHighScore.ToString)

            End If

            Me.nScore = 0 ' restart

            Me.nTicks = 0

            oTimer.Start()

        Else

            Me.Text = Me.nScore.ToString + " " + Int(Me.nMaxSecs - nSecs).ToString

            For i = 0 To MAXLETS - 1

                With Me.aLets(i)

                    If .Visible Then

                        .Left -= .dx

                        If .Left <= 0 Then

                            .Visible = 0

                 Me.BadOne(100)

                        End If

                    Else

                        Dim nFactor = nSecs / Me.nMaxSecs ' 0 - 1

                        If oRand.NextDouble < 0.5 * nFactor Then

                            .dx = 1 + oRand.NextDouble * 15 * nFactor

                            .Left = Me.Width - .dx - 10

                            .ForeColor = Color.FromArgb(Me.nTicks * 100 Mod 256)

                            .Top = 0.8 * (oRand.NextDouble * Me.Height)

                            .Text = Chr(Int(65 + oRand.NextDouble * 26)) ' note: VB Rounds, so we need to use Int()

                            .Visible = 1

                        End If

                    End If

                End With

            Next

        End If

    End Sub

    Sub BadOne(ByVal nHowBad As Integer)

        Me.nScore = Math.Max(0, Me.nScore - nHowBad)

        Beep(2000, 20)

    End Sub

    Class MyLabel

        Inherits Label

        Public dx As Integer = 1

        Sub New()

            Me.Visible = 0

            Me.Height = 32

            Me.Width = 26

            Me.Font = New Font("Verdana", 20, FontStyle.Bold)

            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)

            Me.BackColor = Color.Transparent

        End Sub

    End Class

End Class