IT tutorials
 
Mobile
 

Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 6) - Updated GameplayScreen Class, Collision Detection and Memory Management

5/22/2013 4:19:12 AM
- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire

7. Updated GameplayScreen Class

When you click "new game" in the main menu, the GameplayScreen is the screen that loads and the GameplayScreen class is where all of the game action occurs. The following sections cover how the GameplayScreen class manages the game objects, collision detection, and scoring.

7.1. GamePlay Screen Initialization

Now we are ready to modify the GameplayScreen class to manage the game objects. We declare the object instances needed:

//Game objects
GameStatusBoard statusBoard;
List<AlienGameObject> enemies;
int maxEnemies = 5;
UserGameObject heroShip;
int maxMissiles = 3;

//Indicates to draw game over frame;
bool drawGameOverFrame = false ;

The maxMissiles and maxEnemies variable are not a constant because we may want to change it dynamically during the game as part of the game play. Otherwise, one UserGameObject named heroShip and a List of AlienGameObjects are the other key components of the game. Another potential modification would be to increase the number of AlienGameObjects in the game as the score gets higher to make it more interesting. Otherwise a player will get bored if nothing changes.

Next we load and initialize assets in LoadContent():

public override void LoadContent()
{
  if (content == null)
    content = new ContentManager(ScreenManager.Game.Services, "Content");

  gameFont = content.Load<SpriteFont>("gamefont");
  alienShooterSpriteSheet = content.Load<SpriteSheet>("Sprites/AlienShooterSpriteSheet");
  backgroundTexture = content.Load<Texture2D>("Textures/background");
  backgroundPosition = new Vector2(0, 34);
  //Get a pointer to the entire screen Rectangle
  screenRect = ScreenManager.GraphicsDevice.Viewport.Bounds;

  //Initialize Enemies collection
  enemies = new List<AlienGameObject>();
  for (int i = 0; i < maxEnemies; i++)
  {
    enemies.Add(new AlienGameObject(alienShooterSpriteSheet, "spaceship", screenRect));
  }

  //Initialize Player Object
  heroShip = new UserGameObject(alienShooterSpriteSheet, "heroship", screenRect, maxMissiles);
  heroShip.Position = new Vector2(screenRect.Width / 2, 720);
  heroShip.LoadContent(content);

  //Initialize Status Board
  statusBoard = new GameStatusBoard(gameFont);
  statusBoard.LoadContent(content);

  // A real game would probably have more content than this sample, so
  // it would take longer to load. We simulate that by delaying for a
  // while, giving you a chance to admire the beautiful loading screen.
  Thread.Sleep(1000);

  // once the load has finished, we use ResetElapsedTime to tell the game's
  // timing mechanism that we have just finished a very long frame, and that
  // it should not try to catch up.
  ScreenManager.Game.ResetElapsedTime();
}

					  

By breaking out our game assets into objects it greatly unclutters the code in GameplayScreen class. As an example, initializing the enemies object is a matter of passing in the texture information for the animations:

//Initialize Enemies collection
enemies = new List<AlienGameObject>();

for (int i = 0; i < maxEnemies; i++)
{
  enemies.Add(new AlienGameObject(alienShooterSpriteSheet, "spaceship", screenRect));
}

					  

7.2. GameplayScreen Update and Draw Methods

Addingsupport for the heroShip and the AlienGameObject to the GameplayScreen.Update method is pretty straightforward now that we have nice objects that manage work for us:

public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                bool coveredByOtherScreen)
{
  if (IsActive)
  {
    if (!statusBoard.GameOver)
    {
      CheckForCollisions();

      heroShip.Update(gameTime);
      statusBoard.Update(gameTime);

      for (int i = 0; i < maxEnemies; i++)
      {
        enemies[i].Update(gameTime);
      }
    }
  }
  base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
}

If StatusBoard.GameOver is not true, i.e. the hero ship has lives available, the game action continues. Otherwise, the code is straightforward, calling Update for each object. Notice the call to the CheckForCollisions method. We cover collision detection in the next sub section.

Adding support for user input is just as easy by adding a call to heroShip.HandleIpnut(input) just after the else in the GameplayScreen.HandleInput method. For the GameplayScreen.Draw method the Draw method is called for each object. If StatusBoard.GameOver is true, the Draw method is not called for the enemies any further and the game is over.

public override void Draw(GameTime gameTime)
{
  ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
                                      Color.SlateBlue, 0, 0);

  // Our player and enemy are both actually just text strings.
  SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

  spriteBatch.Begin();
  //Draw Background
  spriteBatch.Draw(backgroundTexture, backgroundPosition, Color.White);
  //Draw Status Board
  statusBoard.Draw(gameTime, spriteBatch);
  //Draw Hero Ship
  heroShip.Draw(gameTime, spriteBatch);

//Draw enemies
  if (!statusBoard.GameOver)
  {
    for (int i = 0; i < maxEnemies; i++)
    {
      enemies[i].Draw(gameTime, spriteBatch);
    }
  }
  spriteBatch.End();

  // If the game is transitioning on or off, fade it out to black.
  if (TransitionPosition > 0)
    ScreenManager.FadeBackBufferToBlack(1f - TransitionAlpha);
}

8. Collision Detection and Memory Management

In the GameplayScreen.Update method, there is a call to the CheckForCollisions method. This method detects collisions between inflight missiles and enemy alien ships (a score) as well as collisions between enemy alien ships and the hero ship (lose a life). Here is the code for the CheckForCollisions method:

private void CheckForCollisions()
{
  //Checking for two major collisions
  //1 - Has an in flight missile intersected an alien spaceship - score 5 pts
  for (int i = 0; i < heroShip.MaxNumberofMissiles; i++)
    if (heroShip.Missiles[i].Alive)
      for (int j = 0; j < maxEnemies; j++)
        if ((enemies[j].Alive) &&
            (enemies[j].BoundingRect.Intersects(heroShip.Missiles[i].BoundingRect)))
        {
          statusBoard.Score += 5;
          enemies[j].ResetGameObject();
          heroShip.Missiles[i].ResetGameObject();
        }
  //2 - Has an alien spaceship intersected the hero ship - deduct a life
  for (int j = 0; j < maxEnemies; j++)
    if ((enemies[j].Alive) && (enemies[j].Position.Y > 600) &&
        (enemies[j].BoundingRect.Intersects(heroShip.BoundingRect)))
    {
      statusBoard.Lives -= 1;
      for (int i = 0; i < maxEnemies; i++)
        enemies[i].ResetGameObject();
      for (int i = 0; i < heroShip.MaxNumberofMissiles; i++)
        heroShip.Missiles[i].ResetGameObject();
    }
}

					  

For detecting a hit by a missile by an alien ship, each missile's bounding box must be compared with each enemy alien ship's bounding box. Same goes for detecting a collision between an enemy ship and the hero ship to lose a life. Each one must be compared every frame for the most part. This means that every time two objects are compared, which could be every frame, two new bounding boxes must be constructed. Remember the bounding box includes a position for the bounding box as well as height and width. Here is the code to return a bounding box in the GameObject base class as a refresher:

public virtual Rectangle BoundingRect
{
  get
  {
    return new Rectangle((int)Position.X, (int)Position.Y,
      SpriteAnimationSpriteSheet.SourceRectangle(SpriteName + 0).Width,
      SpriteAnimationSpriteSheet.SourceRectangle(SpriteName + 0).Height);
  }
}

In a mobile application you want to try to minimize memory allocations to reduce garbage collection activity. In a mobile game, it is especially important to watch memory allocations. As an example, when an enemy is destroyed by a hit, the AlienGameObject for that enemy has its Alive property set to false. We could instead set the object to null and then instantiate a new object but that just wastes CPU cycles on garbage collection.

Another way to minimize CPU cycles is to only do work if needed. Notice in the CheckforCollisions method that the if statements are structured to only perform work and get a BoundingRect when needed. As an example, an enemy alien ship can only intersect the hero ship after it has fallen about two/thirds of the way down the screen so a check is made to only perform the collision calculations if the alien ship is below 600 pixels on the screen.

if ((enemies[j].Alive) && (enemies[j].Position.Y > 600) &&
    (enemies[j].BoundingRect.Intersects(heroShip.BoundingRect)))

Part of game development is always looking for ways to do things smartly. For myself, it is one of the most enjoyable parts of the effort.

 
Others
 
- Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 5) - Missile Class, Game Status Board Class
- Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 4) - Hero Ship Class
- Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 3) - Enemy Class
- Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 2) - Game Object Class
- Windows Phone 7 : Building 2D Games with the XNA Framework - AlienShooter Game Play (part 1) - Sprite Animation
- BlackBerry Bold 9700 and 9650 Series : Connect as a Tethered Modem (part 3) - Using Desktop Manager for Mac
- BlackBerry Bold 9700 and 9650 Series : Connect as a Tethered Modem (part 2) - Using Desktop Manager for Windows
- BlackBerry Bold 9700 and 9650 Series : Connect as a Tethered Modem (part 1) - Understanding the Options for Tethering
- Android 3 : Employing Basic Widgets - Fleeting Images, Fields of Green...or Other Colors
- Android 3 : Employing Basic Widgets - Assigning Labels
 
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
programming4us programming4us
 
Popular tags
 
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS