Key Control

If you followed the previous tutorial, then you may have an idea of what it might take to get things updated after a mouse click. Now we are going to expand it so that things update after a key press. So, based on the previous code, we remove the entire Click event procedure.
    Dim B As Integer
    Dim Backup As System.Drawing.Bitmap  'Memory buffer - will be drawn in one fell swoop.
    Dim GFX, FGFX As System.Drawing.Graphics   'Should draw to the memory buffer declared above.

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Backup = New Bitmap(200, 200)  '200x200 is the size of the memory bitmap, which will 
        'effectively be the size of the display, since nothing can go off of it.
        GFX = Graphics.FromImage(Backup)  'Draws to the memory buffer.
        FGFX = Me.CreateGraphics()  'Draws to the display (form).
    End Sub


    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        Present()
    End Sub

    Private Sub Present()
        FGFX.DrawImage(Backup, 0, 0)
        'Present the memory bitmap to the display.
    End Sub

    Private Sub Clock_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Clock.Tick
        Present()
    End Sub
        int b;
        System.Drawing.Bitmap backup;  //Memory bitmap that will hold drawings that will be drawn all at once.
        System.Drawing.Graphics gfx, fgfx;   //Draws the drawings to the memory bitmap above.

        private void clock_Tick(object sender, EventArgs e)
        {
            Present();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            backup = new Bitmap(200, 200);
            //200x200 is the size of the memory bitmap, which is effectively going to be the display size.
            gfx = Graphics.FromImage(backup);
            //Set gfx to draw to this backup bitmap.
            fgfx = this.CreateGraphics();
            //Set fgfx to draw to the display (form).
        }

        void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            Present();           
        }

        void Present()
        {
            fgfx.DrawImage(backup, 0, 0);
            //Present memory bitmap to the display.
        }
And then, we add the KeyDown event to the form. Also, don't forget to set the KeyPreview property of the form to True. It probably won't make much of a difference, but better safe than sorry, right?
    Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        Me.Text = "OK"
    End Sub
        void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            this.Text = "OK";
        }
Now, the next step, of course, is to get some character moving along on the screen by way of the arrow keys. The first thing we do is not to run into the KeyDown event and start checking for keycodes: we don't even have anything to move. So, first we need to create something to move. Out of the items in the System.Drawing namespace that we can use, there is the Point and the Rectangle. The Rectangle is a point and size combined into one structure. Since the Rectangle is a structure, we are not obligated to have a constructor for it. However, there is a constructor that you can use if you wanted. New Rectangle(L, T, W, H) is kind of like a function that returns this rectangle (not so much a sub as it is a function, however it must become a rectangle). There is also the shared function (it is a function) Rectangle.FromLTRB(L, T, R, B) where you specify the right and bottom end instead of the size (width and height). R = L + W and B = T + H.
Anyway, enough about Rectangles. We are going to declare a rectangle that we will move around with the keys, and this rectangle will be drawn to the display. Our drawing will be done in the timer event (Clock_Tick) since that is when we will notice the changes (and that is when Present is called, which updates the display).
    Dim Self As Rectangle 'Current player's locations.

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Backup = New Bitmap(200, 200)  '200x200 is the size of the memory bitmap, which will 
        'effectively be the size of the display, since nothing can go off of it.
        GFX = Graphics.FromImage(Backup)  'Draws to the memory buffer.
        FGFX = Me.CreateGraphics()  'Draws to the display (form).

        Self = New Rectangle(100, 100, 10, 10)   'Set up player locations.
    End Sub
    Private Sub Clock_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Clock.Tick
        GFX.FillRectangle(Brushes.Blue, Self)
        GFX.DrawRectangle(Pens.LightBlue, Self)
        'Draw the rectangle.
        Present()
    End Sub

        System.Drawing.Rectangle self;  //Current player's location.

        private void clock_Tick(object sender, EventArgs e)
        {
            gfx.FillRectangle(Brushes.Green, self);
            gfx.DrawRectangle(Pens.Lime, self);
            //Draw current player.
            Present();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            backup = new Bitmap(200, 200);
            //200x200 is the size of the memory bitmap, which is effectively going to be the display size.
            gfx = Graphics.FromImage(backup);
            //Set gfx to draw to this backup bitmap.
            fgfx = this.CreateGraphics();
            //Set fgfx to draw to the display (form).

            self = new Rectangle(100, 100, 10, 10);
            //Setup player's location.
        }
Next, key events? Well, no. We need a background first, otherwise we get slime trails. If you don't want a background, then you do not need to use IMFD (Iceplug Method of Flickerless Display).
    Private Sub Clock_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Clock.Tick
        GFX.FillRectangle(Brushes.Black, Me.ClientRectangle)
        'Draw the background.
        GFX.FillRectangle(Brushes.Blue, Self)
        GFX.DrawRectangle(Pens.LightBlue, Self)
        'Draw the rectangle.
        Present()
    End Sub
        private void clock_Tick(object sender, EventArgs e)
        {
            gfx.FillRectangle(Brushes.Black, this.ClientRectangle);
            //Draw the background.
            gfx.FillRectangle(Brushes.Green, self);
            gfx.DrawRectangle(Pens.Lime, self);
            //Draw current player.
            Present();
        }
Now, we can mess with the key events. The simplest way is just to check if the keycode matches your keycode, and if so, move the rectangle. You can move the Rectangle by doing Self.Left += 10, but there is also the .Offset function which does that for us as well. So, in the KeyDown event:
    Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        'Check keycode against left, right, up, and down.
        If e.KeyCode = Keys.Left Then
            Self.Offset(-10, 0)  'move left by 10.
        ElseIf e.KeyCode = Keys.Right Then
            Self.Offset(10, 0)  'move right by 10... etc.
        ElseIf e.KeyCode = Keys.Up Then
            Self.Offset(0, -10)
        ElseIf e.KeyCode = Keys.Down Then
            Self.Offset(0, 10)
        End If
    End Sub
        void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            // Check keycode against left, right, up, and down.
            if (e.KeyCode == Keys.Left)
            {
                self.Offset(-10, 0);  //Move left
            }
            else if (e.KeyCode == Keys.Right)
            {
                self.Offset(10, 0);  //Right... etc.
            }
            else if (e.KeyCode == Keys.Up)
            {
                self.Offset(0, -10);
            }
            else if (e.KeyCode == Keys.Down)
            {
                self.Offset(0, 10);
            }
        }
Now, this should be pretty sufficient for most applications. However, if you want seamless movement (ignoring Key Repeat Delay and Repeat Rate), you don't have to resort to the GetAsyncKeyState API. Essentially, all the GetAsyncKeyState will tell you that you need to know is if a key is pressed or not. But, as long as the form receives the keys, you don't need to worry about this. If a key is pressed down, then the KeyDown event is fired. If the key is released, the KeyUp event is fired. So, in order to check if a key is down, we just need to have a boolean that is set to True in the KeyDown event, and set to False in the KeyUp event. However, this is one Boolean per key: for the four keys we are using, we need four booleans. So, in the Key events, each key is associated with a boolean variable, and these boolean variables can be checked to determine if the key associated with it is pressed down. This check has to be done in the timer; it would be pointless to check it in the key events. So, our key checks are like this:
    Dim GoLeft, GoRight, GoUp, GoDown As Boolean  'booleans that indicate the keystate of navigation keys.

    Private Sub Form1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
        'Check keycode against left, right, up, and down.
        If e.KeyCode = Keys.Left Then
            GoLeft = True
        ElseIf e.KeyCode = Keys.Right Then
            GoRight = True
        ElseIf e.KeyCode = Keys.Up Then
            GoUp = True
        ElseIf e.KeyCode = Keys.Down Then
            GoDown = True
        End If
    End Sub
    Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyUp
        'Check keycode against left, right, up, and down.
        If e.KeyCode = Keys.Left Then
            GoLeft = False
        ElseIf e.KeyCode = Keys.Right Then
            GoRight = False
        ElseIf e.KeyCode = Keys.Up Then
            GoUp = False
        ElseIf e.KeyCode = Keys.Down Then
            GoDown = False
        End If
    End Sub
        bool goleft, goright, goup, godown;  //Indicates keystates for these keys.

        void Form1_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            // Check keycode against left, right, up, and down.
            if (e.KeyCode == Keys.Left)
            {
                goleft = true;
            }
            else if (e.KeyCode == Keys.Right)
            {
                goright = true;
            }
            else if (e.KeyCode == Keys.Up)
            {
                goup = true;
            }
            else if (e.KeyCode == Keys.Down)
            {
                godown = true;
            }
        }
        void Form1_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            // Check keycode against left, right, up, and down.
            if (e.KeyCode == Keys.Left)
            {
                goleft = false;
            }
            else if (e.KeyCode == Keys.Right)
            {
                goright = false;
            }
            else if (e.KeyCode == Keys.Up)
            {
                goup = false;
            }
            else if (e.KeyCode == Keys.Down)
            {
                godown = false;
            }
        }
And then, we check the booleans in the timer's tick event in order to move the rectangle.
    Private Sub Clock_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Clock.Tick
        'Move player location first.
        Movement()

        GFX.FillRectangle(Brushes.Black, Me.ClientRectangle)
        'Draw the background.
        GFX.FillRectangle(Brushes.Blue, Self)
        GFX.DrawRectangle(Pens.LightBlue, Self)
        'Draw the rectangle.
        Present()
    End Sub
    Private Sub Movement()
        If GoLeft Then
            Self.Offset(-10, 0)  'Move left.
        End If
        If GoRight Then
            Self.Offset(10, 0)   'Move right... etc.
        End If
        If GoUp Then
            Self.Offset(0, -10)
        End If
        If GoDown Then
            Self.Offset(0, 10)
        End If
    End Sub
        private void clock_Tick(object sender, EventArgs e)
        {
            //Do player movement before drawing the player.
            movement();
            gfx.FillRectangle(Brushes.Black, this.ClientRectangle);
            //Draw the background.
            gfx.FillRectangle(Brushes.Green, self);
            gfx.DrawRectangle(Pens.Lime, self);
            //Draw current player.
            Present();
        }
        private void movement()
        {
            if (goleft)
            {
                self.Offset(-10, 0);
            }
            if (goright)
            {
                self.Offset(10, 0);
            }
            if (goup)
            {
                self.Offset(0, -10);
            }
            if (godown)
            {
                self.Offset(0, 10);
            }
        }
And this will allow seamless movement. In addition, the separated checks for each key allow the character to move diagonally.