IT tutorials
 
Technology
 

Windows Phone 7 : XNA Game Studio and Framework Overview (part 2) - Implement the Game

8/23/2013 9:40:46 AM
- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

2. Implement the Game

In this section we start with the default game loop code generated when we created the HelloXNA project to create a simple space ship shooter game. Our game will be a simple top-down shooter where alien space ships attempt to strike the hero ship. The hero ship can shoot missiles at the alien ships to cause them to explode. Score is based on the number of alien ships blown up.

Now that we have an understanding of the game play, let's get started. We alternate between coding and background detail as we develop the game to explain key concepts. In the Game1.cs code file we declare four variables of type Texture2D named HeroShip, SpaceShip, Missile, and BackgroundImage that are initialized in the LoadContent method:

HeroShip = this.Content.Load<Texture2D>("Sprites/heroship");
SpaceShip = this.Content.Load<Texture2D>("Sprites/spaceship");
Missile = this.Content.Load<Texture2D>("Sprites/missile");
BackgroundImage = this.Content.Load<Texture2D>("Textures/background");

Since these assets are loaded by a ContentManager object, we do not need to worry about releasing the objects in the UnloadContent method. The ContentManager will take care of that for us when it goes out of scope.

Now that we loaded the content, we next cover modifications to the Update() and Draw() methods. We cover Draw first because we want to draw the background on the screen. To actually do the drawing to the graphics device you use a SpriteBatch object.

By default, the XNA Game Studio project template creates a member named spritePatch of type SpriteBatch. Within the Draw method, you first call spriteBatch.Begin, then spriteBatch.Draw any number of times, and then spriteBatch.End.It is more efficient for the graphics hardware to draw to the back buffer as a batch and then draw to the back buffer to the device as opposed to drawing items one at a time directly to the graphics device.SpriteBatch.Begin method sets up the back buffer and the call to SpriteBatch.End indicates that the batch is ready to be drawn to the device.

spriteBatch.Begin();
spriteBatch.Draw(BackgroundImage,graphics.GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.End();


Figure 3 shows the background image in the Emulator.

Figure 3. Drawing the background in the Emulator

The background is static for our simple game so we are finished with it. We covered Begin and End for the SpriteBatch class but not the Draw method, which has several overloads that look intimidating at first, taking rectangle objects, rotation, scale, etc.

All overloads of the Draw method have a couple of parameters in common in that all of the overloads take a Texture2D(the image to draw) and a position to draw it either in the form of a Vector2 or a Rectangle object. For the background image shown in Figure 3, we draw with this overload:

spriteBatch.Draw(BackgroundImage,graphics.GraphicsDevice.Viewport.Bounds, Color.White);


BackgroundImage is the Texture2D to be drawn. For the place to draw the texture, we pass in the Rectangle size of the entire screen, which is defined by graphics.GraphicsDevice.Viewport.Bounds. We could hard-code the values to be the shipping screen resolution of 800 × 480. However, we do not want to hardcode this value, because at some point in the future an additional screen resolution will be introduced that is 480 × 320. The last parameter in this Draw method overload allows you to tint Texture2D in a particular color. Color.White represents no tint at all.

Now let's shift over to the Update method. It is in the Update method where calculations are performed to determine where the alien ship, space ship, and missile should be drawn. In addition to the variable representing the sprite image, we also need variables to track the position and speed of the objects as well. First let's have a quick discussion on vectors.

When Windows Phone 7 initially hits the market, the screen resolution is 800 pixels in height and 480 pixels in width. In XNA Framework, the 2D coordinate system puts 0,0 in the upper left hand corner of the screen with the positive X direction flowing to the right and positive Y direction flowing down the screen, as shown in Figure 4.

Figure 4. The Windows Phone 7 Portrait 2D Cartisian Plane


A Vector2 consists of an X and Y component that represents a direction and magnitude from the origin. As an example, since the screen is 480 pixels wide, the XVector2 would have zero for the Y component, and 480 for the X component like this (480,0). Likewise, a Vector2 that represents the Y axis would have zero for the X component and 800 for the Y component like this (0,800). axis represented as a

A Vector2 can represent either a position or a speed. As a position, you set the X and Y component to be the values you want to place an object on the Cartesian plane. As an example, to place the upper left-hand corner of a sprite or image in the middle of the screen, you would set the sprites position to this value (240,400), which is half the screen width and height respectively.

When you position a sprite, it is always relative to the upper left-hand corner of the sprite, which is considered (0,0) in terms of height and width for the sprite. If you don't take this into account and think you are positioning the center of a sprite, it will be off by half the height of the sprite toward the bottom and half the width of the sprite to the right.


Position is pretty straightforward in a 2D plane. Representing Speed as a Vector2 is similar except that the Vector2 is interpreted by its magnitude or length and direction. Imagine an arrow with its tail at position (0,0) and its head at (X,Y) such as (10,10) on a 2D plane, as illustrated in Figure 5.

Figure 5. Vectors in a 2D plane

If the imaginary Vector2 (0,10) represents a speed, it means that the object is moving straight down at 10 pixels per frame. If the Vector2 (10,10) represents a speed, it means that for each frame, the object is moving 10 pixels to the right and 10 pixels down. Figure 6 depicts a ball that has a position of (300, 160). A speed Vectors2 (50,50) is applied to the ball in a given frame.

Figure 6. Applying speed to an object via vector addition

Applying a speed of (50,50) redirects the ball to a southeastern direction in the plane, giving a new position of (350, 210) for the ball. We know this intuitively because X is positive to the right and Y is positive in the down position, so the Vector2 (50,50) moves the ball 50 pixels to the right and 50 pixels down. Note that we could just as easily have a speed of (-50, 50), which would intuitively move the ball to the southwest direction.

Now that you have a basic understanding of position and speed as Vector2 objects, let's go back to the XNA Game Studio project. We will perform speed and position calculations in the Update method. We also need to check to see if an object has either collided with another object/sprite, or if the object collided with an edge of the screen.

If it an object collides with an object we can do several things. If the object is a golf club and the other object represents a golf ball, a developer would want to simulate the club connecting with the ball and send it flying in the opposite direction based on the ball and club Vector2 position, the angle of impact. Another example action upon a collision is that if the collision is between an alien space ship and a missile fired from the player's space ship, the game could simulate an explosion and the alien space ship disappears from the screen.

Speaking of the player space ship, the other key component handed in the Update method is user input, which is also calculated using Vector2 objects. For Windows Phone 7 user input can be in the form of a screen tap, a gesture, or the accelerometer as the major game input methods.

With the background on the screen coordinate system and Vector2D objects out of the way, you should have a pretty good idea of what the code will look like in the Update method in pseudo code:

  • Handle User Input

  • Apply User Input to objects

  • Update Position of objects

  • Detect Object and Edge Collisions

  • Determine the final state and position of all objects

A key point to consider is that if the Update method takes too long the Game loop will decide to skip a call to the Draw method, resulting in dropped frames. Keep this in mind when writing code in the Update method.

Armed with an understanding of what we need to do in the Update method in general, let's dive into coding the game logic. We need to add a couple of member variables to represent the position and speed for our game objects, which include the hero ship, the enemy space ship, and the missile. We need to track each object's position, and speed so we declare six additional variables:

//Define Speed and Position vectors for objects that move
Vector2 HeroShipPosition;
Vector2 HeroShipSpeed;
Vector2 SpaceShipPosition;
Vector2 SpaceShipSpeed;
Vector2 MissilePosition;
Vector2 MissileSpeed;

We initialize these values in a separate method named InitializeObjects executed in LoadContent just after we load the related sprite images.

private void InitializeObjects()
{
//Initialize Positon and Speed
SpaceShipPosition = new Vector2(
graphics.GraphicsDevice.Viewport.Width / 2 - SpaceShip.Width / 2, -SpaceShip.Height);
SpaceShipSpeed = new Vector2(0, 2); // 2 pixels / frame "down"

//Center hero ship width wise along the X axis
//Place hero ship with 20 pixels underneath it in the Y axis
HeroShipPosition = new Vector2(



graphics.GraphicsDevice.Viewport.Width / 2 - HeroShip.Width / 2,
graphics.GraphicsDevice.Viewport.Height - HeroShip.Height - 20f);
HeroShipSpeed = Vector2.Zero;

//Center Missile on Space Ship and put it 50 pixels further down
//off screen "below" hereoship
MissilePosition = HeroShipPosition +
new Vector2(HeroShip.Width / 2 - Missile.Width / 2, HeroShip.Height + 20f);
MissileSpeed = new Vector2(0, −6); // 6 pixels / frame "up"

}


I mentioned this earlier but it is worth restating: when you draw a sprite, the position provided to the Draw method is the origin of the sprite when drawn meaning that the provided position becomes the upper left-hand corner of the sprite. In order to draw the alien spaceship and hero spaceship centered width-wise on the screen, we subtract half of the sprite's width from the position so that the middle of the sprite is centered on the screen.

I already covered how to draw in the Draw method, and we are already drawing the background, which was easy to position since it fills the entire screen. We haven't written the code to draw the hero ship, the alien spaceship, or the missile. Since we now have position information for these objects to reference in the form of the initialized variables, let's update the Draw method. We add these three lines of code to the Draw method right after we draw the background image:

spriteBatch.Draw(SpaceShip, SpaceShipPosition, Color.White);
spriteBatch.Draw(Missile, MissilePosition, Color.White);
spriteBatch.Draw(HeroShip, HeroShipPosition, Color.White);

Figure 7 shows the results.

Figure 7. Sprite Initial Position

We are pretty much down with the Draw method for our simple game and will focus on the Update method to make the game interactive. The first thing we do is add the basic update formula for all three objects to the Update method:

HeroShipPosition += HeroShipSpeed;
SpaceShipPosition += SpaceShipSpeed;
MissilePosition += MissileSpeed;

If you run the game right now, you will see the enemy spaceship move down the screen and the missile move up the screen at a slightly faster rate. Figure 8 shows a snapshot of the movement.

Figure 8. Moving Sprites

While pretty cool, it doesn't do much. The sprites pass through each other and then fly off to infinity in the up direction for the missile and the down direction for the alien spaceship. We can make a couple of modifications to make it somewhat more interesting as well as explain a couple of concepts.

The first modification that we make is edge detection. In the Update Method we type CheckScreenBoundaryCollision(gameTime); and then right-click on it and select Generate => Method Stub.

In the newly generated method, we check to see if the missile, which has a default speed of −4 pixels / frame in the Y direction, has flown off the top of the screen, which would be a negative Y value. Since the alien space ship drops straight down at 2 pixels per frame, we check to see if it has a Y value greater than the screen height. Here is the method:

private void CheckScreenBoundaryCollision(GameTime gameTime)
{
//Reset Missile if off the screen
if (MissilePosition.Y < 0)
{
MissilePosition.Y = graphics.GraphicsDevice.Viewport.Height -
HeroShip.Height;
}

//Reset enemy spaceship if off the screen
//to random drop point
if (SpaceShipPosition.Y >
graphics.GraphicsDevice.Viewport.Height)
{
SpaceShipPosition.Y = -2*SpaceShip.Height;
}
}

Notice that we avoid using actual number values. As an example, we could use 480 instead of graphics.GraphicsDevice.Viewport.Height, but when the second screen resolution becomes available the game will break, because screen height in landscape mode will be 320.

The second modification to the game is to detect collisions between the alien spaceship and the missile. We create a new method, CheckForCollisions(gameTime); as before and edit the generated stub. There are many different algorithms available to detect for collisions with different levels of accuracy. The most accurate method is to compare for equality each point of the first image with every possible point in the other image. While most accurate, it is also the most CPU intensive and time consuming.

A simple method to check for collisions is to use bounding boxes. The idea is to wrap an object in a rectangle and check for collisions. The rectangle is based on the maximum length and width of the object. This can be inaccurate for irregular shapes, but costs much less in terms of CPU and time. In our simple game we generate two Rectangle objects that wrap the alien spaceship and the missile and then call the Intersects method to detect a collision. Here is the code:

private void CheckForCollisions(GameTime gameTime)
{
//Alien and Missile
Rectangle AlienRec = new Rectangle((int)SpaceShipPosition.X,
(int)SpaceShipPosition.Y,SpaceShip.Width, SpaceShip.Height);
Rectangle MissileRec = new Rectangle((int)MissilePosition.X,
(int)MissilePosition.Y,Missile.Width, Missile.Height);

if (AlienRec.Intersects(MissileRec))
{
SpaceShipPosition.Y = -2*SpaceShip.Height;
MissilePosition.Y = graphics.GraphicsDevice.Viewport.Height - HeroShip.Height;
}
}


We create the two Rectangle objects and then check for collision by calling if (AlienRec.Intersects(MissileRec)) and then update position similar to when there is a screen edge collision.

We now have an application that shows a dropping alien spaceship intersected by a missile over and over again. While not the most functional game, specifically because it doesn't incorporate user input or interactivity at all, it allows us to demonstrate key concepts for XNA Game Studio without inundating you with new concepts. Listing 2 shows the full code for our incomplete game.

Example 2. Modified Game1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;

namespace HelloXNA
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game


{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;

//Define Texture2D objects to hold game content
Texture2D HeroShip;
Texture2D SpaceShip;
Texture2D BackgroundImage;
Texture2D Missile;

//Define Speed and Position vectors for objects that move
Vector2 HeroShipPosition;
Vector2 HeroShipSpeed;
Vector2 SpaceShipPosition;
Vector2 SpaceShipSpeed;
Vector2 MissilePosition;
Vector2 MissileSpeed;

public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";

// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);

}

/// <summary>
/// Allows the game to perform any initialization it needs to before starting to run.
/// This is where it can query for any required services and load any non-graphic
/// related content. Calling base.Initialize will enumerate through any components
/// and initialize them as well.
/// </summary>
protected override void Initialize()
{
// TODO: Add your initialization logic here

base.Initialize();
}

/// <summary>
/// LoadContent will be called once per game and is the place to load
/// all of your content.
/// </summary>
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);

HeroShip = this.Content.Load<Texture2D>("Sprites/heroship");
SpaceShip = this.Content.Load<Texture2D>("Sprites/spaceship");
Missile = this.Content.Load<Texture2D>("Sprites/missile");
BackgroundImage = this.Content.Load<Texture2D>("Textures/background");



InitializeObjects();
}

private void InitializeObjects()
{
//Initialize Positon and Speed
SpaceShipPosition = new Vector2(
graphics.GraphicsDevice.Viewport.Width / 2 - SpaceShip.Width / 2, -SpaceShip.Height);
SpaceShipSpeed = new Vector2(0, 2); // 2 pixels / frame "down"

//Center hero ship width wise along the X axis
//Place hero ship with 20 pixels underneath it in the Y axis
HeroShipPosition = new Vector2(
graphics.GraphicsDevice.Viewport.Width / 2 - HeroShip.Width / 2,
graphics.GraphicsDevice.Viewport.Height - HeroShip.Height - 20f);
HeroShipSpeed = Vector2.Zero;

//Center Missile on Space Ship and put it 50 pixels further down
//off screen "below" hereoship
MissilePosition = HeroShipPosition +
new Vector2(HeroShip.Width / 2 - Missile.Width / 2, HeroShip.Height + 20f);
MissileSpeed = new Vector2(0, −6); // 6 pixels / frame "up"

}

/// <summary>
/// UnloadContent will be called once per game and is the place to unload
/// all content.
/// </summary>
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}

/// <summary>
/// Allows the game to run logic such as updating the world,
/// checking for collisions, gathering input, and playing audio.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();

// TODO: Add your update logic here
CheckScreenBoundaryCollision(gameTime);
CheckForCollisions(gameTime);

HeroShipPosition += HeroShipSpeed;
SpaceShipPosition += SpaceShipSpeed;
MissilePosition += MissileSpeed;

base.Update(gameTime);
}

private void CheckForCollisions(GameTime gameTime)
{
//Alien and Missile
Rectangle AlienRec = new Rectangle((int)SpaceShipPosition.X,
(int)SpaceShipPosition.Y, SpaceShip.Width, SpaceShip.Height);
Rectangle MissileRec = new Rectangle((int)MissilePosition.X,
(int)MissilePosition.Y, Missile.Width, Missile.Height);

if (AlienRec.Intersects(MissileRec))
{
SpaceShipPosition.Y = −2 * SpaceShip.Height;
MissilePosition.Y = graphics.GraphicsDevice.Viewport.Height - HeroShip.Height;
}
}

private void CheckScreenBoundaryCollision(GameTime gameTime)
{
//Reset Missile if off the screen
if (MissilePosition.Y < 0)
{
MissilePosition.Y = graphics.GraphicsDevice.Viewport.Height -
HeroShip.Height;
}

//Reset enemy spaceship if off the screen
//to random drop point
if (SpaceShipPosition.Y >
graphics.GraphicsDevice.Viewport.Height)
{
SpaceShipPosition.Y = −2 * SpaceShip.Height;
}
}

/// <summary>
/// This is called when the game should draw itself.
/// </summary>
/// <param name="gameTime">Provides a snapshot of timing values.</param>
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);

// TODO: Add your drawing code here
spriteBatch.Begin();
spriteBatch.Draw(BackgroundImage, graphics.GraphicsDevice.Viewport.Bounds, Color.White);
spriteBatch.Draw(SpaceShip, SpaceShipPosition, Color.White);
spriteBatch.Draw(Missile, MissilePosition, Color.White);
spriteBatch.Draw(HeroShip, HeroShipPosition, Color.White);
spriteBatch.End();


base.Draw(gameTime);
}
}
}
 
Others
 
- Windows Phone 7 : XNA Game Studio and Framework Overview (part 1) - Hello XNA for Windows Phone
- Windows Phone 7 : Silverlight Tools and Framework Overview
- Active Directory 2008 : Implementing Group Policy (part 5)
- Active Directory 2008 : Implementing Group Policy (part 4) - Registry Policies in the Administrative Templates Node
- Active Directory 2008 : Implementing Group Policy (part 3) - Policy Settings
- Active Directory 2008 : Implementing Group Policy (part 2) - Group Policy Objects
- Active Directory 2008 : Implementing Group Policy (part 1) - An Overview and Review of Group Policy
- Microsoft Lync Server 2010 : Front End and User Migration to Lync Server 2010 (part 2) - Automatic Client Upgrade , Decommission Process
- Microsoft Lync Server 2010 : Front End and User Migration to Lync Server 2010 (part 1)
- Microsoft Lync Server 2010 : Migrating from LCS and OCS - Edge Server Migration to Lync Server 2010
 
 
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
Technology FAQ
- Is possible to just to use a wireless router to extend wireless access to wireless access points?
- Ruby - Insert Struct to MySql
- how to find my Symantec pcAnywhere serial number
- About direct X / Open GL issue
- How to determine eclipse version?
- What SAN cert Exchange 2010 for UM, OA?
- How do I populate a SQL Express table from Excel file?
- code for express check out with Paypal.
- Problem with Templated User Control
- ShellExecute SW_HIDE
programming4us programming4us