XNA and Visual Basic–Your First Lesson

Computer Science Teacher
Computer Science Teacher - Thoughts and Information from Alfred Thompson

XNA and Visual Basic–Your First Lesson

Rate This
  • Comments 3

image

I have been playing with Visual Basic and XNA for a few days now. Support has been out for VB and XNA for a little while now but the release of the Windows Phone Developer Tools 7.1 Beta and a new document on Visual Basic Support in XNA Game Studio (Mango) has really kicked me into trying it out. As much as I like C# Visual Basic has long been my language of choice for programming for fun.  So after I wrote my first VB game for Windows Phone (Windows Phone 7 Games in Visual Basic) I decided to jump a step back (sideways?) to Windows gaming and an old standby – Pong. Pong is sort of a “Hello World” for game development. So where do you start? Well the first thing you need to know is that there are four and a half methods that you absolutely have to write code for to create an XNA game.

  • Initialize – Set the initial state. Basically get everything ready in a known stable configuration.
  • LoadContent – Bring the images, sound files and any other “content” into the running program.
  • Update – Make work happen. Do stuff. This is the main game loop generally.
  • Draw – Once everything is set draw the pictures and make things appear on the screen.

The half? Well you are probably going to need to declare some variables at the class level so you can get at them from the various methods. For our pong game we’ll need several variables – for the paddles, the ball, the images we will draw and some variables for keep track of things like random numbers and what is happening with the way the user interacts with the game.  We’ll want to create this game to work with or without Xbox game controllers so we want to track the keyboard as well as controllers.

Private WithEvents graphics As GraphicsDeviceManager
Private WithEvents spriteBatch As SpriteBatch
 
Dim t_paddle1 As Texture2D
Dim t_paddle2 As Texture2D
Dim t_ball As Texture2D
 
Dim paddle1 As Paddle
Dim paddle2 As Paddle
Dim ball As Ball
 
Dim rand As New Random()
Dim currentState As KeyboardState
Dim currentPad As GamePadState

You’ll note that we have two variables of type Paddle and one of type Ball. This is to help us control those objects better and we’ll look at the code for them a little further on down the post. For now let us look at Initialize.

Protected Overrides Sub Initialize()
 
    ResetGame()
 
    MyBase.Initialize()
End Sub

I’ve added a call to ResetGame to the Initialize method that Visual Studio created for us when we told it we wanted a Windows XNA game project. By having the reset game code in a separate method (subroutine) we can reuse it other places if and when appropriate. The purpose is to set all the variables to a known state like so:

Private Sub ResetGame()
    paddle1 = New Paddle(10, 200)
    paddle2 = New Paddle(770, 200)
    ball = New Ball(385, 285)
End Sub

We’re just creating new instances of paddles and a ball and placing them at specific locations. The Constructor for the classes helps us out here.

Now let us look at loading the content. In this case we need texture(or image) files for the paddles and the ball.  We’ll have added the image files (you can borrow these two images that I borrowed from Sam Stokes Smile Save them as Ball.png, paddle1.png and paddle2.png)

ballpaddle1paddle2

Protected Overrides Sub LoadContent()
    ' Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = New SpriteBatch(GraphicsDevice)
 
    t_paddle1 = Content.Load(Of Texture2D)("paddle1")
    t_paddle2 = Content.Load(Of Texture2D)("paddle2")
    t_ball = Content.Load(Of Texture2D)("ball")
 
End Sub

Now let’s do some work in Update.

Protected Overrides Sub Update(ByVal gameTime As GameTime)
    ' Allows the game to exit
    If GamePad.GetState(PlayerIndex.One).Buttons.Back = ButtonState.Pressed Then
        Me.Exit()
    End If
 
    UpdateBall()
    UpdatePaddles()
    CheckCollisions()
 
 
    MyBase.Update(gameTime)
End Sub

Once again I have used method calls to keep things simple, organized and easier to maintain. Now for what those methods look like. First things first – move the ball. What we are doing here is changing the X and Y locations of the ball on the screen. We want to make sure it bounces off the bottom. We will check for collisions with the paddles and going off the screen later.

Private Sub UpdateBall()
    'update positions
    ball.pos.X += ball.h_speed
    ball.pos.Y += ball.v_speed
 
    'check for boundaries
    'bottom
    If ball.pos.Y > (Window.ClientBounds.Height - 10 - t_ball.Height) Then
        ball.v_speed *= -1
    End If
 
    'top
    If ball.pos.Y < 10 Then
        ball.v_speed *= -1
    End If
End Sub

In update paddles I am checking both the game controllers (looking for two of them) and the keyboard. I am using the W (for up) and X (for down) keys to controll the paddle on the left and the up and down arrow keys to controll the paddle on the right.

Private Sub UpdatePaddles()
 
        'get keyboard keys
        currentState = Keyboard.GetState()
        Dim currentKeys As Keys() = currentState.GetPressedKeys()
        'check for up and down arrow keys
        For Each key As Keys In currentKeys
            If key = Keys.Up Then
                paddle2.pos.Y -= paddle2.speed
            End If
            If key = Keys.Down Then
                paddle2.pos.Y += paddle2.speed
            End If
            If key = Keys.W Then
                paddle1.pos.Y -= paddle1.speed
            End If
            If key = Keys.X Then
                paddle1.pos.Y -= paddle1.speed
            End If
            If key = Keys.Escape Then
                Me.[Exit]()
            End If
        Next
 
 
        'get controller information
        currentPad = GamePad.GetState(PlayerIndex.One)
 
        'check for up and down arrow keys
        If currentPad.Triggers.Left > 0.0 Then
            paddle1.pos.Y -= paddle1.speed
        End If
 
        If currentPad.Triggers.Right > 0.0 Then
            paddle1.pos.Y += paddle1.speed
        End If
 
        currentPad = GamePad.GetState(PlayerIndex.Two)
 
        'check for up and down arrow keys
        If currentPad.Triggers.Left > 0.0 Then
            paddle2.pos.Y -= paddle2.speed
        End If
 
        If currentPad.Triggers.Right > 0.0 Then
            paddle2.pos.Y += paddle2.speed
        End If
 
 
 
        'check boundaries
        If paddle1.pos.Y <= 10 Then
            paddle1.pos.Y = 10
        End If
        If paddle2.pos.Y <= 10 Then
            paddle2.pos.Y = 10
        End If
 
        If paddle1.pos.Y + t_paddle1.Height >= Window.ClientBounds.Height - 10 Then
            paddle1.pos.Y = Window.ClientBounds.Height - t_paddle1.Height - 10
        End If
        If paddle2.pos.Y + t_paddle2.Height >= Window.ClientBounds.Height - 10 Then
            paddle2.pos.Y = Window.ClientBounds.Height - t_paddle2.Height - 10
        End If
    End Sub

The last thing we do in Update is to check for collisions. Now that the paddles and the ball are in new locations are there any two in the same or overlapping locations?

Private Sub CheckCollisions()
       'check paddle1 if ball moving left, else check paddle2
       If ball.h_speed < 0 Then
           'check if ball has surpassed paddle
           If ball.pos.X < paddle1.pos.X + 20 Then
               'check if ball has hit paddle or went through
               If (ball.pos.Y + t_ball.Height < paddle1.pos.Y) OrElse (ball.pos.Y > paddle1.pos.Y + t_paddle1.Height) Then
                   'LOST!
                   ResetGame()
               Else
                   'ball hit - calculate new speeds
                   'speed of ball changes randomly - 3 to 6
                   If ball.h_speed < 0 Then
                       ball.h_speed = rand.[Next](3, 7)
                   Else
                       ball.h_speed = rand.[Next](-6, -2)
                   End If
 
                   If ball.v_speed < 0 Then
                       ball.v_speed = rand.[Next](3, 7)
                   Else
                       ball.v_speed = rand.[Next](-6, -2)
                   End If
               End If
           End If
       Else
           'check if ball has surpassed paddle
           If ball.pos.X + t_ball.Width > paddle2.pos.X Then
               'check if ball has hit paddle or went through
               If (ball.pos.Y + t_ball.Height < paddle2.pos.Y) OrElse (ball.pos.Y > paddle2.pos.Y + t_paddle2.Height) Then
                   'LOST!
                   ResetGame()
               Else
                   'ball hit - calculate new speeds
                   'speed of ball changes randomly - 3 to 6
                   If ball.h_speed < 0 Then
                       ball.h_speed = rand.[Next](3, 7)
                   Else
                       ball.h_speed = rand.[Next](-6, -2)
                   End If
 
                   If ball.v_speed < 0 Then
                       ball.v_speed = rand.[Next](3, 7)
                   Else
                       ball.v_speed = rand.[Next](-6, -2)
                   End If
               End If
           End If
       End If
   End Sub

If you read through there carefully you will notice that we are calling ResetGame if the ball escapes the right or left boundary of the screen. Code reuse at its finest!

Now let’s draw things!

Protected Overrides Sub Draw(ByVal gameTime As GameTime)
    GraphicsDevice.Clear(Color.CornflowerBlue)
 
    spriteBatch.Begin()
    spriteBatch.Draw(t_paddle1, New Rectangle(paddle1.pos.X, paddle1.pos.Y, t_paddle1.Width, t_paddle1.Height), Color.White)
    spriteBatch.Draw(t_paddle2, New Rectangle(paddle2.pos.X, paddle2.pos.Y, t_paddle2.Width, t_paddle2.Height), Color.White)
    spriteBatch.Draw(t_ball, New Rectangle(ball.pos.X, ball.pos.Y, t_ball.Width, t_ball.Height), Color.White)
    spriteBatch.[End]()
 
    MyBase.Draw(gameTime)
End Sub

The spriteBatch tool is helpful here.

That is the game code. We do need our classes for the ball and paddles though. Here is the ball class. We locate the ball at a specified position passed via the constructor and we select a random speed and direction. This is a fun area to play with the make the game harder or easier BTW.

Public Class Ball
    'position of ball
    Public pos As Point
    Public h_speed As Integer, v_speed As Integer
 
    'constructor - position
    Public Sub New(x As Integer, y As Integer)
        pos = New Point(x, y)
 
        Dim rand As New Random()
        h_speed = rand.[Next](3, 7)
        If rand.[Next](0, 2) = 0 Then
            h_speed *= -1
        End If
 
        rand = New Random()
        v_speed = rand.[Next](3, 7)
        If rand.[Next](0, 2) = 0 Then
            v_speed *= -1
        End If
    End Sub
 
End Class

Now for the paddles. We et a location in the constructor and specify a speed. Now I am not suggesting that you change the constructor to all the program to set a speed. An unscrupulous programmer night use that to set the speed of the two paddles differently giving one player an edge. Not that I would ever do such a thing of course. But it is a thought.

Public Class Paddle
    'position of paddle
    Public pos As Point
    Public speed As Integer
 
    'constructor - position
    Public Sub New(x As Integer, y As Integer)
        pos = New Point(x, y)
        speed = 6
    End Sub
 
End Class

This is about the most simple Pong game you can create of course. I’d love to see what others do with it. Perhaps create something completely different or perhaps just add scoring and sound or who knows what. Let me know if you do something with it. Thanks.



  • Visual Basic, the next big thing. I heard that any investment in VB will pay off, as you could, for example, program websites with VBScript ;-)

  • I can't seem to install Windows Phone Developer Tools 7.1 Beta.  I have the express editions installed for both VB and C#.  When I try to install the software it tells me I need service pack 1 which is not available for the express editions.

  • I installed Visual Studio Service Pack 1 from www.microsoft.com/.../details.aspx and it did support the Express editions which is what I am running right now.

Page 1 of 1 (3 items)