Animation in VB.NET, Part 1

The article on animation in VB6 was a big hit and taken in well. However, VB6 is an outdated, and now unsupported language, so it was time to update this article to VB.NET. In Part 1, you will cover 2D vector graphics, and the methods required to build your Asteroids game. Because stick animation is simple and pretty well covered in the VB6 article, I will not cover them in this update; however, an updated download is included.

Note: All of the downloadable files for this article are in VS 2008 format.

There are a number of new graphics methods introduced in .NET and a lot of the old methods no longer work. Where one was able, in VB6, to draw lines and arcs directly onto the pictureboxes, this is no longer a valid method in .NET. The method that I'm using is to create a Graphics object from the base image. However, I won't be using the final picturebox but a memory bitmap object, and mapping the image onto the picturebox.

Before you continue, I'd like to note that it is preferable that you have read Part 1 of the VB6 articles before continuing because this article updates the methods detailed there for use in VB.NET.

So, your first task is to create your Bitmap and your Graphics object.

Private MyImage As Bitmap
Private MyGraphic As Graphics

Private Sub Asteroids_Load(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles MyBase.Load
   Mypen = New Pen(Color.Black, 1)
   Timer1 = New Windows.Forms.Timer
   MyImage = New Bitmap(PictureBox1.Width, PictureBox1.Height)
   MyGraphic = Graphics.FromImage(MyImage)

   First = True
   Set_Default()
   Timer1.Interval = 15
   Timer1.Enabled = True
   Dead = False
   Init_const()
   Init_Ast()

End Sub

As you can see the bitmap 'MyImage' is created with the same size as the picturebox the final image will be displayed on. The Graphic object is created from this bitmap. Any draw commands from the Graphics object are automatically placed onto the bitmap image object. This object also offers you the buffering method as discussed in Part 2 of the VB6 articles.

Another difference is that you no longer have the Xor pen function that you used in VB6 to erase and redraw lines. I have spent a considerable amount of time searching for Xor pen examples in .NET with little luck. So, in this instance, you will be clearing your bitmap and drawing each game object, or Sprite, in its current position. Where you may have lost in the need to redraw everything for each frame you gain in not having to store and erase the previous locations of each sprite.

So, after all that, you can see that there was a need to overhaul the core functions of the game to work with this new method; however, the math has all stayed the same.

It's time to move on. During the form load, you set the defaults and initiated your constants and asteroids. These functions have not changed from your VB6 version, and I see no need to repeat them here again. However, in the download the asteroid coordinates have been changed, simply so that the VB6 and VB.NET versions are easier to identify when running.

One sub that has changed and is important to the Graphic methods is the Timer Tick event sub.

Private Sub Timer1_Tick1(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles Timer1.Tick
   MyGraphic.Clear(Color.White)
   If Not Dead Then
      Check_Input()
      Put_Ship()
   Else
      Check_Space()
   End If
   Put_Shots()
   Put_Aster()
   Hit_Aster()
   Check_Stage()
   Do_Score()
   PictureBox1.Image = MyImage
End Sub

Most of this is the same; however, before you begin the game core you clear the Bitmap (via the Graphics object) with white colour. Remember that any method used from the graphics object is applied to the image it was generated from; in this case, your bitmap. Once you have completed the game core, you apply your new bitmap image to the picturebox.

Some may ask why you don't simply use the picturebox to generate your graphics object and draw directly to the picturebox. Yes, in testing, I started with the method of drawing directly to the picturebox and I found one small problem. Every Draw command forced the picturebox to re-render itself, causing a terrible slowdown and image jitter. Therefore, using a bitmap to buffer the image greatly reduces the rendering time.

The next step is to now place the ship onto your image.

Private Sub Put_Ship()
   Dim Cord(2) As Cords_Type
   With Ship
      .Location.X = .Location.X - .Speed * Sin(.Direction * PI / 180)
      .Location.Y = .Location.Y + .Speed * Cos(.Direction * PI / 180)

      If .Location.X >= 640 Then .Location.X = .Location.X - 640
      If .Location.X < 0    Then .Location.X = .Location.X + 640
      If .Location.Y >= 480 Then .Location.Y = .Location.Y - 480
      If .Location.Y < 0    Then .Location.Y = .Location.Y + 480

      For Loop_1 = 0 To 2
         Cord(Loop_1).X = .Location.X - (.Len_Const(Loop_1) * _
            Sin(.Ang_Const(Loop_1) + .Angle * PI / 180))
         Cord(Loop_1).Y = .Location.Y + (.Len_Const(Loop_1) * _
            Cos(.Ang_Const(Loop_1) + .Angle * PI / 180))
      Next Loop_1

   End With
   MyGraphic.DrawLine(Mypen, Cord(0).X, Cord(0).Y, Cord(1).X, Cord(1).Y)
   MyGraphic.DrawLine(Mypen, Cord(1).X, Cord(1).Y, Cord(2).X, Cord(2).Y)
   MyGraphic.DrawLine(Mypen, Cord(2).X, Cord(2).Y, Cord(0).X, Cord(0).Y)

End Sub

Animation in VB.NET, Part 1

Nothing much has changed here, except for the fact that you no longer need to erase the previous copy of the ship. Also, the rendering methods have changed slightly. VB6 used 'Object.Line (x1, y1) - (x2, y2)' where .NET now uses 'Object.DrawLine (Pen, x1, y1, x2, y2)'. You no longer set the drawmode on your object but rather use a pen type in your drawing methods.

As you can see, this greatly simplifies your rendering and also speeds up your game core. Now, look at some of the other rendering functions.

Private Sub Put_Aster()
   Dim Cord(9) As Cords_Type
   For Loop_1 = 0 To 39
      With Asteroids(Loop_1)
         If .Vis Then

            .Location.X = .Location.X + .Speed * Sin(.Direction * PI / 180)
            .Location.Y = .Location.Y - .Speed * Cos(.Direction * PI / 180)
            .Angle = .Angle + .Rotate

            If .Location.X >= 640 Then .Location.X = .Location.X - 640
            If .Location.X < 0    Then .Location.X = .Location.X + 640
            If .Location.Y >= 480 Then .Location.Y = .Location.Y - 480
            If .Location.Y < 0    Then .Location.Y = .Location.Y + 480
            If .Angle >= 360      Then .Angle = .Angle - 360
            If .Angle < 0         Then .Angle = .Angle + 360

            For Loop_2 = 0 To 9
               Cord(Loop_2).X = .Location.X - (.Len_Const(Loop_2) * _
                  Sin(.Ang_Const(Loop_2) + .Angle * PI / 180)) / .Size
               Cord(Loop_2).Y = .Location.Y + (.Len_Const(Loop_2) * _
                  Cos(.Ang_Const(Loop_2) + .Angle * PI / 180)) / .Size
            Next Loop_2

            f .Size > 8 Then
               .Vis = False
            Else
               For Loop_2 = 0 To 8
                  MyGraphic.DrawLine(Mypen, Cord(Loop_2).X, _
                     Cord(Loop_2).Y, Cord(Loop_2 + 1).X, _
                     Cord(Loop_2 + 1).Y)
               Next Loop_2
               MyGraphic.DrawLine(Mypen, Cord(9).X, Cord(9).Y, _
                  Cord(0).X, Cord(0).Y)


               .First = False
            End If
         End If
      End With
   Next Loop_1
End Sub

Private Sub Put_Shots()
   For Loop_1 = 0 To 19
      With Shots(Loop_1)
         If .TTL > 0 Then
            .Location.X = .Location.X - .Speed * Sin(.Direction * PI / 180)
            .Location.Y = .Location.Y + .Speed * Cos(.Direction * PI / 180)
            If .Location.X >= 640 Then .Location.X = .Location.X - 640
            If .Location.X < 0    Then .Location.X = .Location.X + 640
            If .Location.Y >= 480 Then .Location.Y = .Location.Y - 480
            If .Location.Y < 0    Then .Location.Y = .Location.Y + 480
            MyGraphic.DrawRectangle(Mypen, .Location.X - 1, _
               .Location.Y - 1, 2, 2)
            .TTL = .TTL - .Speed

            .First = False
         End If
         If .TTL <= 0 And Not .First Then
            MyGraphic.DrawRectangle(DelPen, .Location.X - 1, _
               .Location.Y - 1, 2, 2)
            .TTL = 0
            .First = True
         End If
      End With
   Next Loop_1
End Sub

Compared to the VB6 version, all of these rendering subs are shorter and quicker. However, they do produce an almost identical output.

In the downloads, there is the updated .NET stick figure project that shows how to render simple sick animation using the method of erasing only parts of the image and redrawing the changes, and the updated .NET Asteroids Project as detailed in this article.



About the Author

Richard Newcombe

Richard Newcombe has been involved in computers since the time of the Commodore 64. Today, he has excelled in programming, and designs. Richard is in his mid 30's and, if or when you looking for him look no further than his computer. Always willing to help and give advice where he can in regard to computer related subjects. At present he is working as a .NET 2008 Software Developer for Syncrony Web Services, South Africa.

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: December 11, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT Market pressures to move more quickly and develop innovative applications are forcing organizations to rethink how they develop and release applications. The combination of public clouds and physical back-end infrastructures are a means to get applications out faster. However, these hybrid solutions complicate DevOps adoption, with application delivery pipelines that span across complex hybrid cloud and non-cloud environments. Check out this …

  • On-demand Event Event Date: October 29, 2014 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 webcast, Gene Kim discusses these survey findings and shares woeful tales of artifact management gone wrong! Gene also shares examples of how high-performing DevOps …

Most Popular Programming Stories

More for Developers

RSS Feeds