Time for action - updating and drawing the player's ship

  1. Add the imposeMovementLimits() helper method to the PlayerManager class:
    private void imposeMovementLimits()
    {
    Vector2 location = playerSprite.Location;
    if (location.X < playerAreaLimit.X)
    location.X = playerAreaLimit.X;
    if (location.X >
    (playerAreaLimit.Right - playerSprite.Source.Width))
    location.X =
    (playerAreaLimit.Right - playerSprite.Source.Width);
    if (location.Y < playerAreaLimit.Y)
    location.Y = playerAreaLimit.Y;
    if (location.Y >
    (playerAreaLimit.Bottom - playerSprite.Source.Height))
    location.Y =
    (playerAreaLimit.Bottom - playerSprite.Source.Height);
    playerSprite.Location = location;
    }
    
  2. Add the Update() method to the PlayerManager class:
    public void Update(GameTime gameTime)
    {
    PlayerShotManager.Update(gameTime);
    if (!Destroyed)
    {
    playerSprite.Velocity = Vector2.Zero;
    shotTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
    HandleKeyboardInput(Keyboard.GetState());
    HandleGamepadInput(GamePad.GetState(PlayerIndex.One));
    playerSprite.Velocity.Normalize();
    playerSprite.Velocity *= playerSpeed;
    playerSprite.Update(gameTime);
    imposeMovementLimits();
    }
    }
    
  3. Add the Draw() method to the PlayerManager class:
    public void Draw(SpriteBatch spriteBatch)
    {
    PlayerShotManager.Draw(spriteBatch);
    if (!Destroyed)
    {
    playerSprite.Draw(spriteBatch);
    }
    }
    
  4. Add a declaration to the Game1 class for the PlayerManager:
    PlayerManager playerManager;
    
  5. In the LoadContent() method of the Game1 class, set up the PlayerManager after the AsteroidManager is initialized:
    playerManager = new PlayerManager(
    spriteSheet,
    new Rectangle(0, 150, 50, 50),
    3,
    new Rectangle(
    0,
    0,
    this.Window.ClientBounds.Width,
    this.Window.ClientBounds.Height));
    
  6. In the Update() method of the Game1 class, add an update line for the PlayerManager right after the AsteroidManager is updated:
    playerManager.Update(gameTime);
    
  7. In the Draw() method of the Game1 class, add a draw line for the PlayerManager right after the AsteroidManager is drawn:
    playerManager.Draw(spriteBatch);
    
  8. Execute the game and fly your star fighter around in the asteroid field. Fire off a few shots with your cannon!

What just happened?

The imposeMovementLimits() method begins by making a copy of the playerSprite's Location property. Since Location is a property and not a public member, we cannot modify the components of the vector (X and Y) individually. Creating a temporary copy allows us to independently modify these values and then save the whole vector back to the property.

The X and Y values of the vector are checked against the edges of the playerAreaLimit rectangle. On the right and bottom edges, the width and height of the player sprite is subtracted from the bounding rectangle edges to ensure that the player sprite stays entirely on the screen. If any of the edges are out of alignment, the components of the location vector are adjusted to keep the ship within the play area.

The location is then saved back into the playerSprite.Location property.

Updating the player manager begins by updating its related ShotManager. Then, if the Destroyed variable is false, the remainder of the Update() method is allowed to proceed. This check prevents the player from continuing to fire shots after being killed. The update begins by setting the player's velocity to zero and incrementing the timer for firing shots. The HandleKeyboardInput() and HandleGamepadInput() methods are then called, passing each the current state of the appropriate input device.

We need to resolve two potential issues with player movement at this point. If the player were simply moving to the right, the player's velocity vector would be equal to (1, 0), with a length of 1 unit. If, however, the player is holding down both the right and up keys, the resulting vector would be (1, 1). As we saw when discussing normalized vectors while bouncing asteroids off of each other, this vector has a length of 1.414 units, meaning that the player can move faster by moving diagonally than they can by moving in straight lines.

A related side issue is that if the player has an Xbox gamepad connected to their PC, they could hold down both the thumbstick and the arrow keys to move at twice the normal speed in their chosen direction.

To compensate for both of these potential issues, the Update() method normalizes the player's velocity vector and then multiplies it by the playerSpeed variable. This results in a vector that is always the same length (unless, of course, the player is not moving, in which case the vector value of (0, 0) has no length at all).

After all of the input and velocity changes have been accounted for, the Update() method of the playerSprite object is called to allow the velocity to be added to the player's location and to advance the animation frame. Finally, the imposeMovementLimits() method is called to make sure the ship stays within the play area.

When the PlayerManager is drawn, the same series of events takes place as the Update() method. First, the associated ShotManager is drawn, followed by a check to see if the player has been destroyed. If they are still alive, the player ship gets drawn to the screen. It is important to note that the ShotManager gets drawn before the player, because any shot the player fires will begin somewhat overlapping the player's sprite. By drawing the shots before the player ship, the shot will appear to come from inside the ship, instead of appearing on top of the ship when fired.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.147.124