In this article I will be covering the Paddle class for the MGS: Pong game. I am not going to cover everything in great detail because it works very much like the Ball class. Let’s get started; below are the private members needed. New members are those that are used for the AI in the game,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #region Private Members private SpriteBatch m_spriteBatch; private ContentManager m_conManager; private Texture2D m_paddleTexture; private string m_texSource; private Vector2 m_position = new Vector2(); private Color m_color = Color.White; private bool m_isAI = false; private Keys m_upKey; private Keys m_dnKey; private float m_speed = 5.0f; private Ball m_ball = null; private bool m_recenter = false; #endregion |
Next we need to handle the constructor as well as loading and unloading the content.
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 | #region Constructor public Paddle (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 #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_paddleTexture = 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_paddleTexture != null ) { m_paddleTexture.Dispose (); m_paddleTexture = null; } // Dispose of the spritebatch // and set it to null. if ( m_spriteBatch != null ) { m_spriteBatch.Dispose (); m_spriteBatch = null; } } } #endregion |
Next we need to handle the paddle’s movement and the AI controlling the paddle. When the AI is handling the movement of the paddle the goal is simple: move the paddle until it is behind the ball. We only do this when the ball is moving towards the paddle because when it is moving away from the paddle it is better to move the paddle back to the center of the screen to minimize the distance it needs to travel next time around. This recentering only occurs on the harder difficulty of AI paddles because of how it works. The last thing to do in the Update method is to handle when a collision occurs. We offset the movement of the ball if the paddle is moving so that the game isn’t just a boring game of back and forth Ping Pong.
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 95 96 97 98 99 100 101 102 103 104 | #region Updating public override void Update (GameTime gameTime) { KeyboardState state = Keyboard.GetState (); float yVel = 0f; // Handle AI movement if ( m_isAI ) { // If the ball is moving towards the paddle, // we need to move it for the computer! if ( m_ball.VelocityX > 0 ) { // If the ball is above the paddle, move upward! if ( m_ball.Y + m_ball.Height < m_position.Y ) { m_position.Y -= m_speed; yVel = -1f; } // If the ball is below the paddle, move downward! else if ( m_ball.Y > Destination.Bottom ) { m_position.Y += m_speed; yVel = 1f; } } // If the ball is moving away, and recentering is on // move the paddle back to the center slowly. else if ( m_recenter ) { // If the paddle is in the top half of the screen, move down if ( Destination.Bottom - (Destination.Height / 2) < GraphicsDevice.Viewport.Height / 2 ) { m_position.Y += m_speed / 4; yVel = 1f; } // If the paddle is in the bottom half of the screen, move up else if ( Destination.Bottom - (Destination.Height / 2) > GraphicsDevice.Viewport.Height / 2 ) { m_position.Y -= m_speed / 4; yVel = -1f; } } } // If the player is handling the paddle, let's // see if there is any input else { // If the up key is down, move up if ( state.IsKeyDown ( m_upKey ) ) { m_position.Y -= m_speed; yVel = -1f; } // If the down key is down, move down. else if ( state.IsKeyDown ( m_dnKey ) ) { m_position.Y += m_speed; yVel = 1f; } } // Check the paddle against the bounds of the screen. if ( m_position.Y + m_paddleTexture.Height > GraphicsDevice.Viewport.Height ) m_position.Y = GraphicsDevice.Viewport.Height - m_paddleTexture.Height; else if ( m_position.Y < 0 ) m_position.Y = 0; if ( m_ball != null ) { // If there is a collision if ( Destination.Intersects ( m_ball.Destination ) ) { // Go back until the ball doesn't intersect the paddle. do { m_ball.X -= m_ball.VelocityX * m_ball.Speed; m_ball.Y -= m_ball.VelocityY * m_ball.Speed; } while ( Destination.Intersects ( m_ball.Destination ) ); // Revert the direction of the ball's X movement m_ball.VelocityX *= -1; // If there is some speed to our paddle, // give the ball some extra speed. if(yVel > 0 || yVel < 0) { // If the movement is equal to the ball's travel, // give it speed. if ( yVel == m_ball.VelocityY ) m_ball.Speed += 1.0f; // Set the direction of the ball's movement. m_ball.VelocityY = yVel; } } } base.Update ( gameTime ); } #endregion |
The last couple of things are just like the Ball class. We provide a Draw method as well as a bunch of properties. In the next article I will cover drawing the background for our game!
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_paddleTexture == null ) return; // Start drawing. m_spriteBatch.Begin ( SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState ); // Draw the paddle. m_spriteBatch.Draw ( m_paddleTexture, m_position, m_color ); // End drawing. m_spriteBatch.End (); } #endregion |
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 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | #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 whether or not the paddle is controlled /// by a player or by the computer. /// </summary> public bool IsAI { get { return m_isAI; } set { m_isAI = value; } } /// <summary> /// Gets or Sets what key controls the down motion of the paddle. /// </summary> public Keys DownKey { get { return m_dnKey; } set { m_dnKey = value; } } /// <summary> /// Gets or Sets what key controls the up motion of the paddle. /// </summary> public Keys UpKey { get { return m_upKey; } set { m_upKey = 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 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 or Sets what ball to interact with the paddle. /// </summary> public Ball Ball { get { return m_ball; } set { m_ball = value; } } /// <summary> /// Gets or Sets whether or not the paddle recenters. /// </summary> public bool ReCenter { get { return m_recenter; } set { m_recenter = value; } } /// <summary> /// Gets the width of the paddle's texture. /// </summary> public int Width { get { return m_paddleTexture.Width; } } /// <summary> /// Gets the height of the paddle's texture. /// </summary> public int Height { get { return m_paddleTexture.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 |