JSEDLAK » Blog Archive » MGS: Pong (Pages 1-3)

MGS: Pong (Pages 1-3)

Before you get started coding, you will need a few more pieces of content for the game. Also note that this article is now using Xna 2.0 and as such will use the new Content project. A list of the content files are below.

  • Content/Fonts/LargeFont.bmp
  • Content/Fonts/MediumFont.bmp
  • Content/Textures/Background.jpg
  • Content/Textures/Paddle.png
  • Content/Textures/Ball.png

Now that you have the content setup in your project, we can get to coding the game. Since C# is an object oriented programming languages, we will build each element of the game into components, one that you could reuse in the next game you create. Below is a diagram showing the relationship between the various classes we are going to create.

As seen here, there will be three basic classes that we will use to create the gameplay. A fourth one, which isn’t listed, will handle the menus. When we build the game in such an abstract and generic way, we allow each component to be used across games and even in the same game. In the diagram, you will note that the relationship to the Ball and Paddle class allows a one to many relationship (1..* and 2..*), meaning that each game can have one or more balls and two or more paddles.

Let’s start by developing the Ball class: go ahead and create a new Ball.cs file. In this class, we will need a slew of private members to handle the motion and the drawing of the ball. We will need a SpriteBatch to draw a texture, ContentManager to load the texture and a Texture2D to store the texture. Also needed is a Vector2 to store the position, a float to scale the velocity Vector2 and a Color to draw the ball a specific color.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#region Private Members
private SpriteBatch m_spriteBatch;
private ContentManager m_conManager;
 
private Texture2D m_ballTexture;
private string m_texSource;
 
private Vector2 m_position = new Vector2 ();
 
private Color m_color = Color.White;
 
private float m_speed = 2.5f;
private Vector2 m_velocity = new Vector2 ( -1, 0 );
#endregion

The next thing to handle is the constructor of the ball class. This is a simple constructor which simply creates the ContentManager.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
#region Constructor
public Ball (Game game)
    : base ( game )
{
    // Instantiates a new Content Manager. The CM class
    // is a lightweight object that allows us to load and
    // process XNA content.
    m_conManager = new ContentManager ( game.Services );
}
#endregion

In Xna 2.0, Microsoft has included two new methods for loading content and made the old methods deprecated (they will work, but are on their way out) to move away from labeling the loading as graphic content only. Loading the actual content works the same, however, and remains fairly simple.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#region Load / Unload Content
protected override void LoadGraphicsContent (bool loadAllContent)
{
    base.LoadGraphicsContent ( loadAllContent );
 
    // Load All Content is true when the Device is created
    // or goes through a hard reset. This happens when the
    // window is created and sometimes when moved to 
    // another monitor.
    if ( loadAllContent )
    {
        // Instantiates a new SpriteBatch object.
        m_spriteBatch = new SpriteBatch ( GraphicsDevice );
 
        // Checks if the texture file exists, and if so
        // loads the texture.
        if ( File.Exists ( m_texSource + ".xnb" ) )
            m_ballTexture = m_conManager.Load<Texture2D> ( m_texSource );
    }
}
 
protected override void UnloadGraphicsContent (bool unloadAllContent)
{
    base.UnloadGraphicsContent ( unloadAllContent );
 
    // Much like loadAllContent, the value of unloadAllContent
    // is true when the device is created or goes through a hard
    // reset. This occurs before a LoadGraphicsContent(...) in
    // the latter cases.
    if ( unloadAllContent )
    {
        // Unloads all the data.
        m_conManager.Unload ();
 
        // Dispose of unmanaged memory and
        // set the paddle texture to null
        if ( m_ballTexture != null )
        {
            m_ballTexture.Dispose ();
            m_ballTexture = null;
        }
 
        // Dispose of the spritebatch
        // and set it to null.
        if ( m_spriteBatch != null )
        {
            m_spriteBatch.Dispose ();
            m_spriteBatch = null;
        }
    }
}
#endregion

Next, the Update method has to handle a few things that can happen to the ball each frame. First it needs to handle when the ball moves above or below the top or bottom of the screen. When this happens we want to bounce the ball off the invisible wall like it would if you bounced a ball off the ground in real life. The next thing is we need to actually move the ball. This uses a speed and a velocity (direction with magnitude of 1) to move the ball.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#region Updating
public override void Update (GameTime gameTime)
{
    // If the ball is below the bottom at all, bounce it back up
    // by negating the y velocity.
    if ( m_position.Y + m_ballTexture.Height > GraphicsDevice.Viewport.Height )
    {
        m_position.Y = GraphicsDevice.Viewport.Height - m_ballTexture.Height;
        m_velocity.Y *= -1;
    }
    // If the ball is above the top at all, bounce it down
    // by negating the y velocity.
    else if ( m_position.Y < 0 )
    {
        m_position.Y = 0;
        m_velocity.Y *= -1;
    }
 
    // Update the position.
    m_position += m_speed * m_velocity;
 
    base.Update ( gameTime );
}
#endregion

The last thing we need to do is actually draw the ball on the screen. This is incredibly straight forward, using the SpriteBatch to draw the texture.

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#region Drawing
public override void Draw (GameTime gameTime)
{
    base.Draw ( gameTime );
 
    // If the texture doesn't exist, we can't draw!
    if ( m_ballTexture == null )
        return;
 
    // Start drawing.
    m_spriteBatch.Begin ( SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState );
 
    // Draw the paddle.
    m_spriteBatch.Draw ( m_ballTexture, m_position, m_color );
 
    // End drawing.
    m_spriteBatch.End ();
}
#endregion

After the draw section I have included properties to allow access to the internal members of the Ball class. These are below in case you have trouble creating them. In the next MGS: Pong article, I will cover how to draw Paddles on the screen, bringing us one step closer to the final product!

?View Code CSHARP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#region Properties
/// <summary>
/// Gets or Sets how fast the paddle can move.
/// </summary>
public float Speed
{
    get { return m_speed; }
    set { m_speed = value; }
}
 
/// <summary>
/// Gets or Sets the X position of the paddle.
/// </summary>
public float X
{
    get { return m_position.X; }
    set { m_position.X = value; }
}
 
/// <summary>
/// Gets or Sets the Y position of the paddle.
/// </summary>
public float Y
{
    get { return m_position.Y; }
    set { m_position.Y = value; }
}
 
/// <summary>
/// Gets or Sets the X component of the ball's velocity.
/// </summary>
public float VelocityX
{
    get { return m_velocity.X; }
    set
    {
        m_velocity.X = value;
    }
}
 
/// <summary>
/// Gets or Sets the Y component of the ball's velocity.
/// </summary>
public float VelocityY
{
    get { return m_velocity.Y; }
    set
    {
        m_velocity.Y = value;
    }
}
 
/// <summary>
/// Gets or Sets the source of the paddle's texture.
/// </summary>
public string TextureSource
{
    get { return m_texSource; }
    set { m_texSource = value; }
}
 
/// <summary>
/// Gets or Sets the color of the paddle.
/// </summary>
public Color Color
{
    get { return m_color; }
    set { m_color = value; }
}
 
/// <summary>
/// Gets the width of the paddle's texture.
/// </summary>
public int Width
{
    get { return m_ballTexture.Width; }
}
 
/// <summary>
/// Gets the height of the paddle's texture.
/// </summary>
public int Height
{
    get { return m_ballTexture.Height; }
}
 
/// <summary>
/// Gets the rendered destination rectangle of the paddle.
/// </summary>
public Rectangle Destination
{
    get { return new Rectangle ( (int)m_position.X, (int)m_position.Y, Width, Height ); }
}
#endregion

Leave a Reply