Rocket Science: Acceleration

Building the Game

The Black Hole game is based on most of the code we’ve developed in each of the previous hours of the book, and there really is no single previous hour that gets more credit than others since each hour has built upon the hours that came before. Let’s dig into the game by going over the major sections and get something up and running fairly quickly. Then we’ll continue our work on the game into the following hour, where it will get some polish and fine-tuning of the fun factor.

This game is based on the theories of Stephen Hawking. If you’re interested in black hole physics, be sure to read his popular books for more information! The Universe in a Nutshell is one of my favorites.

Gravity Well Regions

There are three regions around the black hole that affect game objects. The outer gravity well affects objects passing by, drawing them toward the black hole with relatively light force. This force is increased by an equal amount in the next two inner regions, with each region generating an equivalent gravity “tug” on objects. But the cumulative effect of all three gravity wells in the inner region of the black hole will cause objects to become hopelessly trapped.

The third and innermost region might be thought of as the event horizon, that region of a black hole where things disappear into the void, never to be seen again. It is this region that mathematics cannot penetrate, so while it appears that gravity increases toward infinity in the middle of a black hole, the truth of the matter is, there may be nothing at the very center of a black hole! The gravity might be so powerful that matter just rotates around the center of mass and no matter actually exists at that center point, which would be quite small at the center of a black hole. Then again, there might be a superdense material like a neutron star. It is at this point that physics just cannot explain it, because we don’t actually have a black hole nearby to study. Even if we did, it’s not like a spacecraft could be sent to investigate!

Figure 23.1 shows an illustration of the gravity well of the black hole in the game. The outer gravity well is quite large and draws most game objects inward at a steady “weight” or “pull,” with some help from the inner core of the black hole, also exerting force. The inner gravity well is the region where energy can be mined by the “Hawking” satellites. At any rate, that’s one of the enjoyable aspects of this game, pondering the infinite possibilities!

The code to simulate the gravitational pull of the black hole is coming up. Now let’s just take a look again at some of our earlier helper methods used in this game. All the collision code in the Black Hole game is based around this RadialCollision() method and its overloaded friend:

[code]
public bool RadialCollision(Sprite A, Sprite B)
{
float radius1 = A.image.Width / 2;
float radius2 = B.image.Width / 2;
return RadialCollision(A.position, B.position,
radius1, radius2);
}
public bool RadialCollision(Vector2 A, Vector2 B, float radius1,
float radius2)
{
float dist = Distance(A, B);
return (dist < radius1 + radius2);
}
public float Distance(Vector2 A, Vector2 B)
{
double diffX = A.X – B.X;
double diffY = A.Y – B.Y;
double dist = Math.Sqrt(Math.Pow(diffX, 2) +
Math.Pow(diffY, 2));
return (float)dist;
}
[/code]

The gravity well of the black hole covers most of the Windows Phone screen.
FIGURE 23.1 The gravity well of the black hole covers most of the Windows Phone screen.

Enhancing MassiveObject

Some minor changes need to be made to MassiveObject to support some new features needed in the game that were not in the example in the preceding hour. Following is what the class now looks like, with the new variables and updated constructor:

[code]
class MassiveObject : Sprite
{
public string name;
public bool captured;
public double mass;
public Vector2 acceleration;
public float radius, angle;
public int lifetime, startTime;
public MassiveObject(ContentManager content,
SpriteBatch spriteBatch)
: base(content, spriteBatch)
{
name = “object”;
mass = 1.0f;
acceleration = Vector2.Zero;
radius = 50.0f;
angle = 0.0f;
captured = false;
lifetime = 0;
startTime = 0;
}
// . . . note: some code omitted here
}
[/code]

Game1.cs

There are no changes to be made to Game1.cs, because the main source code file is now PlayingModule.cs. In the final hour coming up, we will again use the game state modules for a more polished gameplay experience.

Gameplay Source Code

The most significant code of the game is found in PlayingModule.cs. If you skipped ahead, you may have missed Hour 21, “Finite State Gameplay,” which explained how to use states to improve a game in many ways. The PlayingModule class is the primary gameplay class where the bulk of the game code will be found. The first lines of code in the class declare all the variables, including the key objects variable, defined as a List of MassiveObjects. We also see the black hole, the super core gravity well, and the player’s ship here, among other things. Figure 23.2 shows the game as it is just getting started, and Listing 23.1 shows the source code for the class.

The Black Hole game soon after startup.
FIGURE 23.2 The Black Hole game soon after startup.

LISTING 23.1 Source Code for the PlayingModule Class

[code]
public class PlayingModule : IGameModule
{
Game1 game;
SpriteFont font;
Random rand;
Sprite background;
MassiveObject blackHole;
MassiveObject superCore;
MassiveObject ship;
float energy = 100.0f;
int startTime, lifetime;
List<MassiveObject> objects;
public PlayingModule(Game1 game)
{
this.game = game;
rand = new Random();
startTime = 0;
lifetime = 4000;
}
public void LoadContent(ContentManager content)
{
font = content.Load<SpriteFont>(“WascoSans”);
background = new Sprite(game.Content, game.spriteBatch);
background.Load(“space”);
background.origin = Vector2.Zero;
blackHole = new MassiveObject(game.Content, game.spriteBatch);
blackHole.Load(“blackhole”);
blackHole.position = new Vector2(500, 240);
blackHole.scale = 2.0f;
blackHole.mass = 40;
blackHole.color = new Color(255, 100, 100, 200);
blackHole.velocityAngular = 0.1f;
superCore = new MassiveObject(game.Content, game.spriteBatch);
superCore.image = blackHole.image;
superCore.position = new Vector2(blackHole.position.X,
blackHole.position.Y);
superCore.scale = blackHole.scale * 0.4f;
superCore.mass = 60;
superCore.color = new Color(200, 100, 100, 180);
superCore.velocityAngular = 4.0f;
superCore.origin = new Vector2(64, 64);
//create objects list
objects = new List<MassiveObject>();
//create player ship
ship = new MassiveObject(game.Content, game.spriteBatch);
ship.Load(“ship”);
ship.position = new Vector2(200, 240);
ship.mass = 100f;
ship.scale = 0.2f;
ship.rotation = MathHelper.ToRadians(90);
}
[/code]

The Update() method is a bit monolithic at this stage, but the code is easier to follow this way than if it had been divided into several smaller methods. I usually divide a method like this when it grows too large to be easily maintained, but since the gameplay code in PlayingModule is only 300 lines long, there isn’t too much to consume here at once. There’s a lot going on here in Update(), but we won’t break up the code listing and break the flow of the code, which can be distracting.

First of all, the blackHole and superCore objects are updated. Then we go into a foreach loop that processes all the MassiveObject objects in the objects list (there’s a tongue twister!). Each object is updated, rotated, and animated. Within the foreach is where the bulk of the code is found for the game.

When one of the satellites grows to a certain size (from collecting energy), that triggers a subset of code here in the foreach block where the player’s ship actually attracts the satellite toward it, using the same code used to simulate the gravitational pull of the black hole on the same objects. The slight gravity “tug” causes the satellites to veer toward the ship and increase the chances of their being caught by it, without making it too easy for the player. After all, the ship doesn’t move yet, it only rotates in place!

Next up is the code that tugs objects inward toward the black hole, if they are in range. Figure 23.3 shows another screenshot of the game, this time with a lot of satellites in orbit. Note the addition of animated asteroids in the scene. The asteroids serve no purpose, but just fill in some detail to make the scene look more interesting. A new asteroid is added every few seconds at a random direction and velocity, and over time they do tend to add up to quite a large mass of rotation around the black hole, which only increases the fun factor. Now, there is also potential use for these asteroid sprites beyond just “for looks.”

A large number of objects are orbiting the black hole, and they tend to fall in quite frequently.
FIGURE 23.3 A large number of objects are orbiting the black hole, and they tend to fall in quite frequently.

Listing 23.2 contains the source code for the Update() method.

It’s quite a challenge to come up with mass values for the black hole, the super core, and each of the objects that not only result in a realistic simulation of gravity’s effect on objects of mass but also make the game fun. Fun is more important than realism, but we want to have a little of both if possible. But when a trade-off is required, always go with that which helps the game to sell: the fun factor.

LISTING 23.2 Source Code for the Update() Method

[code]
public void Update(TouchLocation touch, GameTime gameTime)
{
int time = gameTime.ElapsedGameTime.Milliseconds;
blackHole.Update(gameTime);
blackHole.Rotate();
superCore.Update(gameTime);
superCore.Rotate();
foreach (MassiveObject obj in objects)
{
if (!obj.alive) continue;
obj.Update(gameTime);
obj.Rotate();
obj.Animate(time); //frame animation
obj.Animate(); //mod animation
//allow ship to collect energy satellites for bonus energy
if (obj.scale > 3.0f && obj.name == “satellite”)
{
obj.Attract(ship);
obj.color = Color.White;
if (game.RadialCollision(obj.position, ship.position,
obj.size.X, 40))
{
obj.alive = false;
energy += obj.scale;
}
}
if (!obj.captured)
{
//attract when object is near the black hole
if (game.RadialCollision(obj.position,
blackHole.position, 10, 500))
{
obj.Attract(blackHole);
obj.Attract(superCore);
//is object touching the outer edges of the black hole?
if (game.RadialCollision(obj.position,
blackHole.position, 10, 120))
{
obj.color = Color.Red;
if (obj.name == “satellite”)
{
obj.scale += 0.1f;
energy += 0.5f;
}
obj.Attract(blackHole); //outer black hole
obj.Attract(superCore); //inner black hole
//oh no, object is caught by the black hole!
if (game.RadialCollision(obj.position,
superCore.position, 16, 60))
{
obj.captured = true;
obj.lifetime = 3000;
obj.startTime = (int)
gameTime.TotalGameTime.TotalMilliseconds;
OrbitalMovement anim1 = new OrbitalMovement(
blackHole.position, 10 + rand.Next(40),
obj.rotation, -0.8f);
obj.animations.Add(anim1);
}
}
else
{
obj.color = Color.White;
}
}
}
//when captured, time runs out
if (obj.lifetime > 0)
{
if (obj.startTime + obj.lifetime <
gameTime.TotalGameTime.TotalMilliseconds)
obj.alive = false;
}
//see if object has gone too far out of bounds
if (obj.position.X < -200 || obj.position.X > 1000 ||
obj.position.Y < -200 || obj.position.Y > 700)
obj.alive = false;
}
//update ship
ship.Update(gameTime);
ship.Rotate();
ship.Animate(time);
if (energy <= 0)
{
ship.Attract(blackHole);
//object is caught by the black hole
if (game.RadialCollision(ship.position, superCore.position,
64, 40))
{
ship.captured = true;
ship.lifetime = 3000;
ship.startTime = (int)
gameTime.TotalGameTime.TotalMilliseconds;
OrbitalMovement anim1 = new OrbitalMovement(
blackHole.position, 10 + rand.Next(40),
ship.rotation, -0.8f);
ship.animations.Add(anim1);
}
//done being squished?
if (ship.lifetime > 0)
{
if (ship.startTime + ship.lifetime <
gameTime.TotalGameTime.TotalMilliseconds)
ship.alive = false;
}
}
else
{
energy -= 0.05f;
ship.velocityLinear.X = 0.0f;
}
//check user input
if (touch.State == TouchLocationState.Released)
{
if (touch.Position.X > ship.position.X)
{
CreateSatellite();
}
else
{
if (touch.Position.Y < 200)
ship.velocityAngular = -0.01f;
else if (touch.Position.Y > 280)
ship.velocityAngular = 0.01f;
else
ship.velocityAngular = 0;
}
}
//time to add another random asteroid?
if (startTime + lifetime < gameTime.TotalGameTime.
TotalMilliseconds)
{
startTime = (int)gameTime.TotalGameTime.TotalMilliseconds;
CreateAsteroid();
}
//clean out the dead objects
foreach (MassiveObject obj in objects)
{
if (obj.alive == false)
{
objects.Remove(obj);
break;
}
}
}
[/code]

The Draw() method is next, with its source code in Listing 23.3. This is a rather small method because the gameplay objects are managed.

LISTING 23.3 Source Code for the Draw() Method

[code]
public void Draw(GameTime gameTime)
{
background.Draw();
superCore.Draw();
blackHole.Draw();
ship.Draw();
foreach (MassiveObject obj in objects)
{
if (obj.alive)
{
obj.Draw();
}
}
string text = “Ship rot “ + MathHelper.ToDegrees(
ship.rotation).ToString();
game.spriteBatch.DrawString(font, text, new Vector2(0, 0),
Color.White);
text = “Objects “ + objects.Count.ToString();
game.spriteBatch.DrawString(font, text, new Vector2(0, 20),
Color.White);
text = “Energy “ + energy.ToString(“N0”);
game.spriteBatch.DrawString(font, text, new Vector2(650, 0),
Color.White);
}
[/code]

Finally, we have two helper methods, CreateAsteroid() and CreateSatellite(), that generate a random asteroid and random satellite, respectively. These two methods, shown in Listing 23.4, are quite important to the gameplay because they determine whether the objects will actually move reasonably on the screen. I say reasonably rather than realistically because, again, we don’t want absolute realism; we want some realism with gobs of fun gameplay. The asteroids aren’t important to the gameplay, because they are just for looks, but we do want them to start off in such a way that they end up rotating around the black hole. Likewise, the satellite must be launched in such a way that it moves reasonably well. At this stage, our satellites move at a constant speed, but in the next (and final) hour, we will add GUI controls that allow the player to adjust the power.

LISTING 23.4 Source Code for the CreateAsteroid() and CreateSatellite() Methods

[code]
public void CreateAsteroid()
{
MassiveObject obj = new MassiveObject(game.Content, game.spriteBatch);
obj.Load(“asteroid”);
obj.columns = 8;
obj.totalFrames = 64;
obj.scale = 0.1f + (float)rand.NextDouble();
obj.size = new Vector2(60, 60);
obj.radius = 80;
//randomly place at top or bottom of screen
obj.position = new Vector2(rand.Next(100, 800), -100);
obj.velocityLinear = new Vector2(4.0f, (float)(rand.NextDouble() *
6.0));
if (rand.Next(2) == 1)
{
obj.position.Y = -obj.position.Y;
obj.velocityLinear.Y = -obj.velocityLinear.Y;
}
obj.scale = 0.4f;
obj.mass = 1;
obj.velocityAngular = 0.001f;
obj.lifetime = 0;
obj.name = “asteroid”;
objects.Add(obj);
}
public void CreateSatellite()
{
MassiveObject obj;
obj = new MassiveObject(game.Content, game.spriteBatch);
obj.Load(“plasma32”);
obj.position = ship.position;
obj.mass = 1;
obj.scale = 0.5f;
obj.lifetime = 0;
obj.name = “satellite”;
//calculate velocity based on ship’s angle
float accel = 4.0f;
float angle = ship.rotation – MathHelper.ToRadians(90);
float x = (float)Math.Cos(angle) * accel;
float y = (float)Math.Sin(angle) * accel;
obj.velocityLinear = new Vector2(x,y);
//load energy to launch
energy -= 1;
objects.Add(obj);
}
}
[/code]
This all sounds like fun, but is there even a way to lose the game? Certainly! If the player runs out of energy, the ship will fall into the black hole! At this stage, the ship just loses its “traction” or station-keeping thrusters and is drawn into the black hole, only to be whipped around by the acceleration code. Some sort of fantastic animation will have to be added so that the ship gets sucked into the black hole like the other objects—a task for the next hour! Figure 23.4 shows what happens now if the player runs out of energy. Another improvement to be made in the next hour is an energy bar rather than just a text display. We have a lot of work yet to do on this game, but it’s already showing promise.

Running out of energy spells doom for the poor ship and its crew!
FIGURE 23.4 Running out of energy spells doom for the poor ship and its crew!

Treating Bitmaps as Sprites

Bringing Bitmaps to Life

A sprite is a bitmap with benefits. XNA provides the SpriteBatch class to draw bitmaps with the SpriteBatch.Draw() method, of which there are several overloaded variants. But despite the name, SpriteBatch does not give us “sprite” capabilities from the gameplay perspective. SpriteBatch is a rendering class, used solely for drawing, not “managing” game entities traditionally known as “sprites.” The difference might seem a subtle one, but it’s actually quite a distinction. SpriteBatch might have been a somewhat incorrect name for the class. The “Batch” part of the name refers to the way in which “bitmaps” (not sprites) are drawn—in a batch. That is, all bitmap drawing via SpriteBatch.Draw() is put into a queue and then all the drawing is done quickly when SpriteBatch.End() is called. It’s faster to perform many draw calls at once in this manner, since the video card is going to be switching state only once. Every time SpriteBatch.Begin() and SpriteBatch.End() are called, that involves a state change (which is very slow in terms of rendering). The fewer state changes that happen, the better!

SpriteBatch.Draw() can handle animation, rotation, scaling, and translation (movement). But, without properties, we have to write custom code to do all of these things with just global variables. It can get tedious! We will see how tedious by writing an example using all global variables. Then, for comparison, we’ll write a simple Sprite class and convert the program. This is not just an illustration of how useful object-oriented programming can be (which is true) but to show why we need a Sprite class for gameplay.

SpriteBatch.Draw() works fine. We don’t need an alternative replacement because it can do anything we need. But the code to draw sprites is very specific. If we don’t want to manually draw every character, or vehicle, or avatar in the game, we have to automate the process in some manner. The key to making this work is via properties. A property is a trait or an attribute that partially describes something. In the case of a person, one property would be gender (male or female); other properties include race, height, weight, and age. No single property fully describes a person, but when all (or most) of the properties are considered, it gives you a pretty good idea of what that person looks like.

The simplest and most common property for a sprite is its position on the screen. In the previous hour, we used a variable called Vector2 shipPos to represent the position of the bitmap, and a variable called Texture2D shipImage to represent the image. These two variables were properties for a game object—a spaceship to be used in a sci-fi game. Wouldn’t it be easier to manage both of these properties inside a Sprite class? Before we do that, let’s see whether it’s really that big of a deal to keep track of properties with global variables.

Drawing Lots of Bitmaps

Let’s create a short example. Now, working with just one bitmap is a piece of cake, because there’s only one call to SpriteBatch.Draw(), only one position variable, and only one image variable. When things get messy is when about five or more bitmaps need to be manipulated and drawn. Up to that point, managing variables for four or so images isn’t so bad, but as the number climbs, the amount of manual code grows and becomes unwieldy (like a giant two-handed sword).

[code]
Vector2 position1, position2, position3, position4, position5;
Texture2D image1, image2, image3, image4, image5;
[/code]

It’s not just declaring and using the variables that can be a problem. It’s the ability to use any more than this practically in a game’s sources. But let’s give it a try anyway for the sake of the argument. Figure 6.1 shows the output for this short program, which is a prototype for a solar system simulation we’ll be creating in this hour. The source code is found in Listing 6.1.

The Many Bitmaps Demo program.
FIGURE 6.1 The Many Bitmaps Demo program.

LISTING 6.1 Source code for the Many Bitmaps Demo program, a precursor to a larger project.

[code]
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Vector2 position1, position2, position3, position4, position5;
Texture2D image1, image2, image3, image4, image5;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
TargetElapsedTime = TimeSpan.FromTicks(333333);
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
image1 = Content.Load<Texture2D>(“sun”);
image2 = Content.Load<Texture2D>(“planet1”);
image3 = Content.Load<Texture2D>(“planet3”);
image4 = Content.Load<Texture2D>(“planet2”);
image5 = Content.Load<Texture2D>(“planet4”);
position1 = new Vector2(100, 240-64);
position2 = new Vector2(300, 240-32);
position3 = new Vector2(400, 240-32);
position4 = new Vector2(500, 240-16);
position5 = new Vector2(600, 240-16);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.Draw(image1, position1, Color.White);
spriteBatch.Draw(image2, position2, Color.White);
spriteBatch.Draw(image3, position3, Color.White);
spriteBatch.Draw(image4, position4, Color.White);
spriteBatch.Draw(image5, position5, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
[/code]

Running into Limits with Global Variables

The Many Bitmaps Demo program wasn’t too difficult to deal with, was it? I mean, there were only five bitmaps to draw, so we needed five position variables. But what if there were 20, or 50, or 100? With so many game objects, it would be impossible to manage them all with global variables. Furthermore, that’s bad programming style when there are better ways to do it. Obviously, I’m talking about arrays and collections. But not only is it a quantity issue with regard to the global variables, but if we want to add another property to each object, we’re talking about adding another 20, 50, or 100 variables for that new property!

Let’s rewrite the program using an array. Later in the hour, we’ll work with a list, which is a container class, but for this next step, an array is a little easier to follow. Here is a new version using arrays. The new source code is found in Listing 6.2.

LISTING 6.2 New source code for the program rewritten to more efficiently store the planet bitmaps and vectors in arrays.

[code]
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D[] images;
Vector2[] positions;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
TargetElapsedTime = TimeSpan.FromTicks(333333);
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
images = new Texture2D[5];
images[0] = Content.Load<Texture2D>(“sun”);
images[1] = Content.Load<Texture2D>(“planet1”);
images[2] = Content.Load<Texture2D>(“planet3”);
images[3] = Content.Load<Texture2D>(“planet2”);
images[4] = Content.Load<Texture2D>(“planet4”);
positions = new Vector2[5];
positions[0] = new Vector2(100, 240-64);
positions[1] = new Vector2(300, 240-32);
positions[2] = new Vector2(400, 240-32);
positions[3] = new Vector2(500, 240-16);
positions[4] = new Vector2(600, 240-16);
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
for (int n = 0; n < 5; n++)
{
spriteBatch.Draw(images[n], positions[n], Color.White);
}
spriteBatch.End();
base.Draw(gameTime);
}
}
[/code]

As you examine the code in this version of the program, what stands out? I notice that in ContentLoad(), the initialization code is actually a bit more complicated than it was previously, but the code in Draw() is shorter. We’re not counting lines of code, but in Draw(), the for loop could accommodate 100 or 1,000 objects with the same amount of code. This is the most significant difference between this and the previous program—we now can handle any arbitrary number of objects.

We could shorten the code in LoadContent() even further by building the filename for each planet. The key is to make the asset names consistent. So, if we rename ”sun” to ”planet0”, then loading the assets becomes a simple for loop. Here is an improvement:

[code]
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
images = new Texture2D[5];
positions = new Vector2[5];
for (int n = 0; n < 5; n++)
{
string filename = “planet” + n.ToString();
images[n] = Content.Load<Texture2D>(filename);
}
positions[0] = new Vector2(100, 240 – 64);
positions[1] = new Vector2(300, 240 – 32);
positions[2] = new Vector2(400, 240 – 32);
positions[3] = new Vector2(500, 240 – 16);
positions[4] = new Vector2(600, 240 – 16);
}
[/code]

The positions array must still be set manually due to the differences in the sizes of the planet images. But I think we could automate that as well by looking at the width and height of each image. The point is not just to make the code shorter, but to find ways to improve the code, make it more versatile, more reusable, and easier to modify. Using a consistent naming convention for asset files will go a long way toward that end.

Creating a Simple Sprite Class

Now let’s experiment with some code that actually does something interesting besides drawing fixed images. We’ll start by creating a simple class to encapsulate a sprite, and then add some features to make the Sprite class useful. This will be a hands-on section where we build the Sprite class in stages. If you are an experienced programmer, you may skip this section.

Creating the Sprite Class

Let’s begin with a new project. The project type will be, as usual, Windows Phone (4.0), and the name is Sprite Demo. In the Game1.cs file, which is the main source code file for the game, we’re going to add the new Sprite class to the top of the file, above the Game1 class. After a while, the Sprite class can be moved into its own file called Sprite.cs. I find this more convenient while working on a new class. See Listing 6.3 for the complete source code.

Classes do not need to be stored in unique source code files; that’s a practice to keep a large project tidy and easier to maintain. But it is acceptable (and often practical) to define a new class inside an existing file. This is especially true when several classes are closely related and you want to better organize the project. The best practice, though, for large classes, is to define each class in its own file.

LISTING 6.3 Source code for the new project with included Sprite class.

[code]
public class Sprite
{
public Texture2D image;
public Vector2 position;
public Color color;
}
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Viewport viewport;
Sprite sun;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
TargetElapsedTime = TimeSpan.FromTicks(333333);
}protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//get screen dimensions
viewport = GraphicsDevice.Viewport;
//create sun sprite
sun = new Sprite();
sun.image = Content.Load<Texture2D>(“sun”);
//center sun sprite on screen
float x = (viewport.Width – sun.image.Width) / 2;
float y = (viewport.Height – sun.image.Height) / 2;
sun.position = new Vector2(x,y);
//set color
sun.color = Color.White;
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
ButtonState.Pressed)
this.Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
//draw the sun
spriteBatch.Draw(sun.image, sun.position, sun.color);
spriteBatch.End();
base.Draw(gameTime);
}
}
[/code]

The code listings in this book omit the using statements at the beginning of every XNA project, as well as the namespace line and surrounding brackets, to focus on just the functional part of a program, only when that code is generated by Visual Studio. You should assume that those lines are required to compile every example listed herein.

Scope and Clarity

This is how most classes begin life, with just some public properties that could have been equally well defined in a struct. In fact, if you just want to create a quick container for a few variables and don’t want to deal with a class, go ahead and do it. Structures (defined as struct) can even have constructor methods to initialize their properties, as well as normal methods. But in a struct, there is no scope; everything is public. In contrast, everything in a class is private by default. This would work, for example:

[code]
struct Sprite
{
Texture2D image;
Vector2 position;
Color color;
}
[/code]

But one limitation with a struct is room for growth; with a class, we can make changes to scope (which means changing whether individual properties and methods are visible outside of the class). At this simplistic level, there’s very little difference between a class and a struct. Some programmers differentiate between them by using structs only as property containers, with no methods, reserving methods only for defined classes. It’s ultimately up to you!

An OOP (object-oriented programming) “purist” would demand that our image, position, and color properties be defined with private scope, and accessed via property methods. The difference between property variables and property methods is fuzzy in C#, whereas they are very clear-cut in a more highly precise language such as C++. Let’s see what the class will look like when the three variables (image, position, and color) are converted into private properties with public accessor methods.

[code]
public class Sprite2 //”good” OOP version
{
Texture2D p_image;
Vector2 p_position;
Color p_color;
public Texture2D image
{
get { return p_image; }
set { p_image = value; }
}
public Vector2 position
{
get { return p_position; }
set { p_position = value; }
}
public Color color
{
get { return p_color; }
set { p_color = value; }
}
}
[/code]

In general, I prefer to not hide property variables (such as public Texture2D image in the Sprite class), because it just requires extra code to access the property later. This is, again, a matter of preference, and might be dependent on the coding standards of your team or employer. If it’s up to you, just focus on writing clean, tight code, and don’t worry about making your code “OOP safe” for others.

Initializing the Sprite Class with a Constructor

Compared to the original Sprite class defined in Game1.cs, what do you think of the “safe” version (renamed to Sprite2 to avoid confusion)? The three variable names have had “p_” added (to reflect that they are now private in scope), and now in their place are three “properly defined” properties. Each property now has an accessor method (get) and a mutator method (set). If you prefer this more highly structured form of object-oriented C#, I encourage you to continue doing what works best for you. But for the sake of clarity, I will use the original version of Sprite with the simpler public access property variables.

Let’s give the Sprite class more capabilities. Currently, it’s just a container for three variables. A constructor is a method that runs automatically when an object is created at runtime with the new operator, for example:

[code]
Sprite sun = new Sprite();
[/code]

The term Sprite(), with the parentheses, denotes a method—the default method since it requires no parameters. Here is ours:

[code]
public class Sprite
{
public Texture2D image;
public Vector2 position;
public Color color;
public Sprite()
{
image = null;
position = Vector2.Zero;
color = Color.White;
}
}
[/code]

Here, we have a new constructor that initializes the class’s properties to some initial values. This is meant to avoid problems later if one forgets to initialize them manually. In our program now, since color is automatically set to Color.White, we no longer need to manually set it, which cleans up the code in LoadContent() a bit.

[code]
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
//get screen dimensions
viewport = GraphicsDevice.Viewport;
//create sun sprite
sun = new Sprite();
sun.image = Content.Load<Texture2D>(“sun”);
//center sun sprite on screen
float x = (viewport.Width – sun.image.Width) / 2;
float y = (viewport.Height – sun.image.Height) / 2;
sun.position = new Vector2(x,y);
}
[/code]

Writing Reusable Code with Abstraction

A usual goal for an important base game class like Sprite is to abstract the XNA code, at least somewhat, to make the class stand on its own as much as possible. This becomes a priority when you find yourself writing games on several platforms. Within the XNA family, we have Windows, Xbox 360, and Windows Phone. But on a larger scale, it’s fairly common to port games to other systems. After you have rewritten your Sprite class a few times for different platforms (and even languages, believe it or not!), you begin to see similarities among the different systems, and begin to take those similarities into account when writing game classes.

There are two aspects that I want to abstract in the Sprite class. First, there’s loading the image. This occurs in LoadContent() when we simply expose the image property to Content.Load(). Second, there’s drawing the sprite. This occurs in Draw(), also when we expose the image property. To properly abstract the class away from XNA, we need our own Load() and Draw() methods within Sprite itself. To do this, the Sprite class must have access to both ContentManager and SpriteBatch. We can do this by passing those necessary runtime objects to the Sprite class constructor. Listing 6.4 contains the new source code for the Sprite class.

LISTING 6.4 Source code for the expanded Sprite class.

[code]
public class Sprite
{
private ContentManager p_content;
private SpriteBatch p_spriteBatch;
public Texture2D image;
public Vector2 position;
public Color color;
public Sprite(ContentManager content, SpriteBatch spriteBatch)
{
p_content = content;
p_spriteBatch = spriteBatch;
image = null;
position = Vector2.Zero;
color = Color.White;
}
public bool Load(string assetName)
{
try
{
image = p_content.Load<Texture2D>(assetName);
}
catch (Exception) { return false; }
return true;
}
public void Draw()
{
p_spriteBatch.Draw(image, position, color);
}
}
[/code]

Putting our new changes into action (in Listing 6.5) reveals some very clean-looking code in LoadContent() and Draw(), with the output shown in Figure 6.2.

LISTING 6.5 Modifications to the project to support the new Sprite features.

[code]
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
viewport = GraphicsDevice.Viewport;
//create sun sprite
sun = new Sprite(Content, spriteBatch);
sun.Load(“sun”);
//center sun sprite on screen
float x = (viewport.Width – sun.image.Width) / 2;
float y = (viewport.Height – sun.image.Height) / 2;
sun.position = new Vector2(x, y);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
sun.Draw();
spriteBatch.End();
base.Draw(gameTime);
}
[/code]

Demonstrating the Sprite class.
FIGURE 6.2 Demonstrating the Sprite class.

Error Handling

The Sprite.Load() method has error handling built in via a try…catch block. Inside the try block is a call to Content.Load(). If the passed asset name is not found, XNA generates an exception error, as shown in Figure 6.3. We don’t want the end user to ever see an exception error, and in a very large game project, it is fairly common for asset files to be renamed and generate errors like this—it’s all part of the development process to track down and fix such common bugs.

To assist, the code in Sprite.Load() returns false if an asset is not found—rather than crashing with an exception error. The problem is, we can’t exit on an error condition from within LoadContent(); XNA is just not in a state that will allow the program to terminate at that point. What we need to do is set a flag and look for it after LoadContent() is finished running.

I have an idea. What if we add a feature to display an optional error message in a pre-shutdown process in the game loop? All it needs to do is check for this error state and then print whatever is in the global errorMessage variable. The user would then read the message and manually shut down the program by closing the window. Let’s just try it out; this won’t be a permanent fixture in future chapters, but you may continue to use it if you want to. First, we need some new variables.

 An exception error occurs when an asset cannot be found.
FIGURE 6.3 An exception error occurs when an asset cannot be found.

[code]
//experimental error handling variables
bool errorState;
string errorMessage;
SpriteFont ErrorFont;
Next, we initialize them.
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = “Content”;
TargetElapsedTime = TimeSpan.FromTicks(333333);
errorMessage = ““;
errorState = false;
}
[/code]

And in LoadContent(), we need to trap the exception error (note that ”sun” was temporarily renamed to ”sun1” to demonstrate the exception error).

[code]
//create sun sprite
sun = new Sprite(Content, spriteBatch);
if (!sun.Load(“sun1”))
{
errorState = true;
errorMessage = “Asset file ‘sun’ not found.”;
return;
}
[/code]

Draw() is where the error handling process comes into play.

[code]
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
//experimental error handler
if (errorState)
{
spriteBatch.DrawString(ErrorFont, “CRITICAL ERROR”,
Vector2.Zero, Color.Red);
spriteBatch.DrawString(ErrorFont, errorMessage,
new Vector2(0,100), Color.Red);
}
else
{
sun.Draw();
}
spriteBatch.End();
base.Draw(gameTime);
}
[/code]

When run again with the new error handling code in place, the previous exception error now becomes a nice in-game notification, as shown in Figure 6.4.

The exception error has been handled nicely.
FIGURE 6.4 The exception error has been handled nicely.

We’ve just scratched the surface of what will be possible with the new Sprite class in this hour. Over the next several chapters, the class will be enhanced significantly, making it possible—with properties and methods—to perform transformations

Getting User Input

Exploring Windows Phone Touchscreen Input

Programming a game’s input system really does require a lot of design consideration ahead of time because all we really can use is the touchscreen! Oh, there is an accelerometer that can be used for input, but it is a rare and often niche game that uses the accelerometer to read the phone’s orientation (the angle and position at which it is being held). The touchscreen, for all practical purposes, is treated like mouse input without a visible mouse cursor. Windows programmers will have a slightly harder time adjusting than someone who has been working with the Xbox 360 or another console, which already requires an adjustment in one’s assumptions about user input. Windows games are a cakewalk, with 100-plus keyboard keys, the mouse, and an optional controller! That’s a lot of input! On the Windows Phone, though, all we have is the touchscreen. So we need to make the most of it, being mindful that a user’s finger is rather large compared to the precise input of a mouse cursor.

For the purpose of detecting input for a game, the most obvious method might be to just detect the touch location and convert that to an average coordinate—like mouse input. But the Windows Phone touchscreen is capable of multitouch, not just single-touch input. Although the screen is very small compared to a tablet or PC screen, it is still capable of detecting input from up to four fingers at once. To develop a multitouch game, you will need the actual Windows Phone hardware— either a real phone or an unlocked development model (with no phone service).

Multitouch is a significant feature for the new phone! For our purposes here, however, we will just be concerned with single “tap” input from one finger, simulated with mouse motion in the emulator. We can do a single tap with a mouse click, or a drag operation by touching the screen and moving the finger across the screen. Again, this will have to be done with your mouse for development on the emulator (unless your Windows system uses a touchscreen!).

You will not be able to test multitouch in the emulator without a multitouch screen on your Windows development system or an actual Windows Phone device.

Simulating Touch Input

The key to touch input with a WP7 device with XNA is a class called TouchPanel. The XNA services for mouse, keyboard, and Xbox 360 controller input are not available in a WP7 project. So, for most XNA programmers, TouchPanel will be a new experience. Not to worry; it’s similar to the mouse code if we don’t tap into the multitouch capabilities.

The TouchPanel class includes one very interesting property that we can parse— MaximumTouchCount represents the number of touch inputs that the device can handle at a time.

The second class that we need to use for touch input is called TouchCollection. As the name implies, this is a collection that will be filled when we parse the TouchPanel while the game is running. TouchCollection has a State property that is similar to MouseState, with the enumerated values Pressed, Moved, and Released.

The Touch Demo Project, Step by Step

Let’s create a sample project to try out some of this code. I’ll skip the usual new project instructions at this point since the steps should be familiar by now. Just create a new project and add a font so that we can print something on the screen. I’ve used Moire Bold 24 as the font in this example.

  1. Add some needed variables for working with text output. (The code for the touchscreen input system will be added shortly.)
    [code]
    public class Game1 : Microsoft.Xna.Framework.Game
    {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    SpriteFont MoireBold24;
    Vector2 position;
    Vector2 size;
    string text = “Touch Screen Demo”;
    [/code]
  2. Initialize the font and variables used in the program.
    [code]
    protected override void LoadContent()
    {
    spriteBatch = new SpriteBatch(GraphicsDevice);
    MoireBold24 = Content.Load<SpriteFont>(“MoireBold24”);
    size = MoireBold24.MeasureString(text);
    Viewport screen = GraphicsDevice.Viewport;
    position = new Vector2((screen.Width – size.X) / 2,
    (screen.Height – size.Y) / 2);
    }
    [/code]
  3. Write the update code to get touch input.
    [code]
    protected override void Update(GameTime gameTime)
    {
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
    ButtonState.Pressed)
    this.Exit();
    //get state of touch inputs
    TouchCollection touchInput = TouchPanel.GetState();
    //look at all touch points (usually 1)
    foreach(TouchLocation touch in touchInput)
    {
    position = new Vector2(touch.Position.X – size.X / 2,
    touch.Position.Y – size.Y / 2);
    }
    base.Update(gameTime);
    }
    [/code]
  4. Print the message on the screen at the touch coordinates.
    [code]
    protected override void Draw(GameTime gameTime)
    {
    GraphicsDevice.Clear(Color.CornflowerBlue);
    spriteBatch.Begin();
    spriteBatch.DrawString(MoireBold24, text, position, Color.White);
    spriteBatch.End();
    base.Draw(gameTime);
    }
    [/code]

Figure 4.1 shows the output of the program running in the WP7 emulator. Although the static figure doesn’t show movement, the message “Touch Screen Demo” moves on the screen with touch input! On a real Windows Phone device, this would work with finger input on the screen.

The Windows Phone hardware specification calls for at least four simultaneous touchscreen inputs!

The text message moves based on touch input.
FIGURE 4.1 The text message moves based on touch input.

How to Simulate More Inputs

What if you really do have a great design for a multitouch game but have no way to test it (that is, you do not have a WP7 device or a touchscreen for your Windows PC)? One alternative is to develop and test your game with simulated inputs for each finger, and then test each input separately in the emulator. This actually works quite well! Suppose your game requires one input to move a ship left or right on the screen, and another input to fire a weapon. The easy approach is to just leave the ship’s movement alone (presumably at the center of the screen without movement) to test the firing input. When that is working satisfactorily, then you might test leftto- right movement input with random or regular shooting intervals. This is how most developers will approach the problem.

Using Gestures on the Touchscreen

A related capability of the TouchPanel class is a gesture interface. This is potentially a really great feature for WP7 games, so don’t pass it up! A gesture is essentially nonverbal communication with your hands. A gesture on a touchscreen might be to flick an object across the screen rather than dragging to the exact location where you want it to go. Instead of manually moving something one direction or another, one might just flick it in the general direction. So, it’s up to the game to interpret the gestures based on the game’s user interface design.

Since gesture input can be used in place of touch input, you might want to just use gesture input instead. If all you need for your game is single-touch input, a tap gesture would work in place of the mouselike touch code seen previously. The main difference between the two methods is that gesture input does not support multitouch.

XNA supports gestures with the same TouchPanel class used for touch input. Here are the contents of the GestureType enumeration:

  • None
  • FreeDrag
  • Tap
  • Pinch
  • DoubleTap
  • Flick
  • Hold
  • DragComplete
  • HorizontalDrag
  • PinchComplete
  • VerticalDrag

Gesture-based input does not support multitouch. Only a single gesture (with one finger) can be used at a time.

To use gesture input, we have to enable it, because gesture input is not automatic. There are obvious problems with input if all gestures are enabled by default, because the game will behave erratically with flick gestures in a game using a lot of “drag”-style input to move and interact with the game. Even the simplest of arcadestyle or puzzle games will involve some dragging of the finger across the screen for input, and this could be misinterpreted as a flick if the intended movement is too fast. To enable both tap and flick gestures, add this line to the constructor, Game1(), or LoadContent():

[code]
TouchPanel.EnabledGestures = GestureType.Tap | GestureType.Flick;
[/code]

A simple example can be added to the Update() method of the Touch Demo to see how it works. Note that the first if condition is required. Trying to read a gesture when none is available will cause an exception!

[code]
if (TouchPanel.IsGestureAvailable)
{
GestureSample gesture = TouchPanel.ReadGesture();
if (gesture.GestureType == GestureType.Tap)
{
position = new Vector2(gesture.Position.X – size.X / 2,
gesture.Position.Y – size.Y / 2);
}
}
[/code]

Running this code, you might be surprised to find that the tap gesture is more like a mouse click-and-release event. Click-dragging does not produce the gesture! You can see for yourself by commenting out the touch input code in the Touch Demo program, and running just the gesture code instead. If you’re really interested in gesture input, a real WP7 device is a must-have! The emulator just doesn’t satisfy. If you are doing WP7 development for profit, a dev device or an actual Windows Phone device (with carrier subscription) is a good investment.

Touch input can be quite satisfying to a game designer after working with the traditional keyboard and mouse, because it offers the potential for very creative forms of input in a game. Although regular multitouch input will be the norm for most Windows Phone games, the ability to use gestures also might prove to be fun.

Printing Text

Creating the Font Demo Project

A font in XNA is nothing more than a text file—at least, from the programmer’s point of view. When the project is compiled, XNA uses the text file to create a bitmap font on a memory texture and use that for printing text on the screen.

This is a time-consuming process, which is why the font is created at program startup rather than while it’s running. Let’s create a new project and add a font to it.

Creating a New XNA Project

Follow these steps to create a new XNA project in Visual C# 2010:

  1. Start up Visual Studio 2010 Express for Windows Phone (or whichever edition of Visual Studio 2010 you are using).
  2. Bring up the New Project dialog, shown in Figure 3.1, from either the Start Page or the File menu.

    Creating the Font Demo project.
    FIGURE 3.1 Creating the Font Demo project.
  3. Choose Windows Phone Game (4.0) from the list of project templates.
  4. Type in a name for the new project (the example is called Font Demo).
  5. Choose the location for the project by clicking the Browse button, or by typing the folder name directly.
  6. Click OK to create the new project.

The new project is generated by Visual Studio and should look similar to the project shown in Figure 3.2.

The newly generated Font Demo project.
FIGURE 3.2 The newly generated Font Demo project.

Adding a New Font to the Content Project

At this point, you can go ahead and run the project by pressing F5, but all you will see in the Windows Phone emulator is a blue screen. That is because we haven’t written any code yet to draw anything. Before we can print text on the screen, we have to create a font, which is added to the Content project.

In XNA 4.0, most game assets are added to the Content project within the Solution, where they are compiled or converted into a format that XNA uses. We might use the general term “project” when referring to a Windows Phone game developed with XNA, but there might be more than one project in the Solution. The “main project” will be the one containing source code for a game. Some assets, however, might be located just within the source code project, depending on how the code accesses those assets. Think of the Content project as a container for “managed” assets.

A Visual Studio “Solution” is the overall wrapper or container for a game project, and should not be confused with “projects” that it contains, including the Content project containing game assets (bitmap files, audio files, 3D mesh files, and so on).

In this example, both the Solution and the main project are called “Font Demo,” because Visual Studio uses the same name for both when a new Solution is generated. Now, let’s add a new font to the Content project. Remember that the Content project is where all game assets are located.

  1. Select the Content project in Solution Explorer to highlight it, as shown in Figure 3.3.

    Highlighting the Content project.
    FIGURE 3.3 Highlighting the Content project.
  2. Open the Project menu and choose Add New Item. Optionally, you can right-click the Content project in Solution Explorer (Font DemoContent (Content)) to bring up the context menu, and choose Add, New Item.
  3. The Add New Item dialog, shown in Figure 3.4, appears. Choose Sprite Font from the list. Leave the name as is (SpriteFont1.spritefont).

    Adding a new Sprite Font.
    FIGURE 3.4 Adding a new Sprite Font.

A new .spritefont file has been added to the Content project, as shown in Figure 3.5. Visual Studio opens the new file right away so that you can make any changes you want to the font details. The default font name is Segoe UI Mono, which is a monospaced font. This means each character of the font has the same width (takes up the same amount of horizontal space). Some fonts are proportional, which means each character has a different width (in which case, “W” and “I” are spaced quite differently, for instance).

A new Sprite Font has been added to the Content project.
FIGURE 3.5 A new Sprite Font has been added to the Content project.

The SpriteFont1.spritefont file is just a text file, like a .CS source code file, but it is formatted in the XML (Extensible Markup Language) format. You can experiment with the font options in the .spritefont descriptor file, but usually the only fields you will need to change are FontName and Size. Here is what the font file looks like with all comments removed:

[code]
<?xml version=”1.0” encoding=”utf-8”?>
<XnaContent xmlns:Graphics =
“Microsoft.Xna.Framework.Content.Pipeline.Graphics”>
<Asset Type=”Graphics:FontDescription”>
<FontName>Segoe UI Mono</FontName>
<Size>14</Size>
<Spacing>0</Spacing>
<UseKerning>true</UseKerning>
<Style>Regular</Style>
<CharacterRegions>
<CharacterRegion>
<Start>&#32;</Start>
<End>&#126;</End>
</CharacterRegion>
</CharacterRegions>
</Asset>
</XnaContent>
[/code]

Visual Studio Solution (.sln) and project (.csproj) files also contain XML-formatted information!

Table 3.1 shows the royalty-free fonts included with XNA 4.0. Note that some fonts come with italic and bold versions even though the SpriteFont description also allows for these modifiers.

XNA Fonts

Learning to Use the SpriteFont Class

We can create as many fonts as we want in an XNA project and use them at any time to print text with different styles. For each font you want to use in a project, create a new .spritefont file. The name of the file is used to load the font, as you’ll see next. Even if you want to use the same font style with a different point size, you must create a separate .spritefont file (although we will learn how to scale a font as a rendering option).

Loading the SpriteFont Asset

To use a SpriteFont asset, first add a variable at the top of the program. Let’s go over the steps:

  1. Add a new variable called SpriteFont1. You can give this variable a different name if you want. It is given the same name as the asset here only for illustration, to associate one thing with another.
    [code]
    public class Game1 : Microsoft.Xna.Framework.Game
    {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    //create new font variable
    SpriteFont SpriteFont1;
    [/code]
  2. Create (instantiate) a new object using the SpriteFont1 variable, and simultaneously load the font with the Content.Load() method. Note the class name in brackets, <SpriteFont>. If you aren’t familiar with template programming, this can look a bit strange. This type of coding makes the code cleaner, because the Content.Load() method has the same call no matter what type of object you tell it to load.
    [code]
    protected override void LoadContent()
    {
    // Create a new SpriteBatch, which can be used to draw textures.
    spriteBatch = new SpriteBatch(GraphicsDevice);
    // TODO: use this.Content to load your game content here
    SpriteFont1 = Content.Load<SpriteFont>(“SpriteFont1”);
    }
    [/code]

If the Content class did not use a templated Load() method, we would need to call a different method for every type of game asset, such as Content.LoadSpriteFont(), Content.LoadTexture2D(), or Content.LoadSoundEffect().

There is another important reason for using a template form of Load() here: We can create our own custom content loader to load our own asset files! XNA is very extendable with this capability. Suppose you want to load a data file saved by your own custom level editor tool. Instead of manually converting the level file into text or XML, which XNA can already read, you could instead just write your own custom content loader, and then load it with code such as this: Content.Load<Level>(“level1”)

The ability to write code like this is powerful, and reflects a concept similar to “late binding.” This means the C# compiler might not know exactly what type of object a particular line of code is referring to at compile time, but the issue is sorted out later while the program is running. That’s not exactly what’s happening here, but it is a similar concept, and the easiest illustration of template programming I can think of.

These are just possibilities. Let’s get back to the SpriteFont code at hand!

Printing Text

Now that we have loaded the .spritefont asset file, and XNA has created a bitmap font in memory after running the code in LoadContent(), the font is available for use. We can use the SpriteFont1 object to print text on the screen using SpriteBatch.DrawString(). Just be sure to always have a matching pair of SpriteBatch.Begin() and SpriteBatch.End() statements around any drawing code.

Here are the steps you may follow to print some text onto the screen using the new font we have created:

  1. Scroll down to the Draw() method in the code listing.
  2. Add the code shown in bold.
    [code]
    protected override void Draw(GameTime gameTime)
    {
    GraphicsDevice.Clear(Color.CornflowerBlue);
    // TODO: Add your drawing code here
    string text = “This is the Segoe UI Mono font”;
    Vector2 position = new Vector2(20, 20);
    spriteBatch.Begin();
    spriteBatch.DrawString(SpriteFont1, text, position, Color.White);
    spriteBatch.End();
    base.Draw(gameTime);
    }
    [/code]

Run the program by pressing F5. The WP7 emulator comes up, as shown in Figure 3.6.

Printing text in the Font Demo program.
FIGURE 3.6 Printing text in the Font Demo program.

The version of SpriteBatch.DrawString() used here is the simplest version of the method, but other overloaded versions of the method are available. An overloaded method is a method such as DrawString() that has two or more different sets of parameters to make it more useful to the programmer. There are actually six versions of DrawString(). Here is an example using the sixth and most complex version. When run, the changes to the text output are dramatic, as shown in Figure 3.7!

[code]
float rotation = MathHelper.ToRadians(15.0f);
Vector2 origin = Vector2.Zero;
Vector2 scale = new Vector2(1.3f, 5.0f);
spriteBatch.DrawString(SpriteFont1, text, position, Color.White,
rotation, origin, scale, SpriteEffects.None, 0.0f);
[/code]

Experimenting with different DrawString() options.
FIGURE 3.7 Experimenting with different DrawString() options.

As you have learned in this hour, the font support in XNA takes a little time to set up, but after a font has been added, some very useful and versatile text printing capabilities are available. We can print text via the SpriteFont.DrawString() method, with many options available such as font scaling and different colors.

Getting Started with Visual C# 2010 for Windows Phone

Visual C# 2010 Express

At the time of this writing, the current version of the development tool for Windows Phone 7 is Visual Studio 2010. To make development simple for newcomers to the Windows Mobile platform, Microsoft has set up a package that will install everything you need to develop, compile, and run code in the emulator or on a physical Windows Phone device—for free. The download URL at this time is http://www.microsoft. com/express/Phone. If you are using a licensed copy of Visual Studio 2010, such as the Professional, Premium, or Ultimate edition, then you will find XNA Game Studio 4.0 and related tools at http://create.msdn.com (the App Hub website). The App Hub website, shown in Figure 2.1, also contains links to the development tools.

The App Hub website has download links to the development tools.
FIGURE 2.1 The App Hub website has download links to the development tools.

The most common Windows Phone developer will be using the free version of Visual C# 2010, called the Express edition. This continues the wonderful gift Microsoft first began giving developers with the release of Visual Studio 2005. At that time, the usual “professional” versions of Visual Studio were still available, of course, and I would be remiss if I failed to point out that a licensed copy of Visual Studio is required by any person or organization building software for business activities (including both for-profit and nonprofit). The usual freelance developer will also need one of the professional editions of Visual Studio, if it is used for profit. But any single person who is just learning, or any organization that just wants to evaluate Visual Studio for a short time, prior to buying a full license, can take advantage of the free Express editions. I speak of “editions” because each language is treated as a separate product. The professional editions include all the languages, but the free Express editions, listed here, are each installed separately:

  • Visual C# 2010 Express
  • Visual Basic 2010 Express
  • Visual C++ 2010 Express

The version of Visual Studio we will be using is called Visual Studio 2010 Express for Windows Phone. This is a “package” with the Windows Phone SDK already prepackaged with Visual C# 2010 Express. (Despite the name, “Visual Studio” here supports only the C# language.) It’s a nice package that makes it very easy to get started doing Windows Phone development. But if you are using Visual Studio 2010 Professional (or one of the other editions) along with the Windows Phone SDK, you will see a lot more project templates in the New Project dialog, shown in Figure 2.2.

The New Project dialog in Visual C# 2010 Express.
FIGURE 2.2 The New Project dialog in Visual C# 2010 Express.
  • Windows Phone Application (Visual C#)
  • Windows Phone Databound Application (Visual C#)
  • Windows Phone Class Library (Visual C#)
  • Windows Phone Panorama Application (Visual C#)
  • Windows Phone Pivot Application (Visual C#)
  • Windows Phone Game (4.0) (Visual C#)
  • Windows Phone Game Library (4.0) (Visual C#)
  • Windows Game (4.0) (Visual C#)
  • Windows Game Library (4.0) (Visual C#)
  • Xbox 360 Game (4.0) (Visual C#)
  • Xbox 360 Game Library (4.0) (Visual C#)
  • Content Pipeline Extension Library (4.0)
  • Empty Content Project (4.0) (Visual C#)

As you can see, even in this limited version of Visual Studio 2010, all the XNA Game Studio 4.0 project templates are included—not just those limited to Windows Phone. The project templates with “(4.0)” in the name come from the XNA Game Studio SDK, which is what we will be primarily using to build Windows Phone games. The first five project templates come with the Silverlight SDK. That’s all we get with this version of Visual Studio 2010. It’s not even possible to build a basic Windows application here—only Windows Phone (games or apps), Windows (game only), and Xbox 360 (obviously, game only). The first five project templates are covered in the next section, “Using Silverlight for WP7.”

Did you notice that all of these project templates are based on the C# language? Unfortunately for Visual Basic fans, we cannot use Basic to program games or apps for Windows Phone using Visual C# 2010 Express. You can install Visual Basic 2010 Express with Silverlight and then use that to make WP7 applications. XNA, however, supports only C#.

We don’t look at Xbox 360 development in this book at all. If you’re interested in the subject, see my complementary book XNA Game Studio 4.0 for Xbox 360 Developers [Cengage, 2011].

Using Silverlight for WP7

Microsoft Silverlight is a web browser plug-in “runtime.” Silverlight is not, strictly speaking, a development tool. It might be compared to DirectX, in that it is like a library, but for rich-content web apps. It’s similar to ASP.NET in that Silverlight applications run in a web browser, but it is more capable for building consumer applications (while ASP.NET is primarily for business apps). But the way Silverlight applications are built is quite different from ASP.NET—it’s more of a design tool with an editing environment called Expression Blend. The design goal of Silverlight is to produce web applications that are rich in media support, and it supports all standard web browsers (not just Internet Explorer, which is a pleasant surprise!), including Firefox and Safari on Mac.

Using Expression Blend to Build Silverlight Projects

Microsoft Expression Blend 4 is a free tool installed with the Windows Phone package that makes it easier to design Silverlight-powered web pages with rich media content support. Blend can be used to design and create engaging user experiences for Silverlight pages. Windows application support is possible with the WPF (Windows Presentation Foundation) library. A key feature of Blend is that it separates design from programming. As you can see in Figure 2.3, the New Project dialog in Blend lists the same project types found in Visual C# 2010 Express.

Expression Blend is a Silverlight development tool for web designers.
FIGURE 2.3 Expression Blend is a Silverlight development tool for web designers.

Let’s create a quick Expression Blend project to see how it works. While working on this quick first project, keep in mind that we’re not building a “Blend” project, but a “Silverlight” project—using Blend. Blend is a whole new Silverlight design and development tool, not affiliated with Visual Studio (but probably based on it). The Silverlight library is already installed on the Windows Phone emulator and actual phones.

Here’s how to create the project:

  1. Create a Windows Phone Application project using the New Project dialog. Click File, New Project.
  2. Blend creates a standard project for Windows Phone, complete with an application title and opening page for the app.
  3. Run the project with Project, Run Project, or by pressing F5. The running program is shown in Figure 2.4.
Our first project with Expression Blend.
FIGURE 2.4 Our first project with Expression Blend.

This is a useless app, but it shows the steps needed to create a new project and run it in the Windows Phone emulator. Did you notice how large the emulator window appears? That’s full size with respect to the screen resolution of WP7. As you’ll recall from the first hour, the resolution is 480×800. That is enough pixels to support 480p DVD movies, but not the 740p or 1080p HD standards. Still, DVD quality is great for a phone! And when rotated to landscape mode, 800×480 is a lot of screen real estate for a game too.

You can make quick and easy changes to the labels at the top and experiment with the design controls in the toolbox on the left. Here you can see that the application title and page title have been renamed, and some images and shapes have been added to the page. Pressing F5 again brings it up in the emulator, shown in Figure 2.5.

Now that you’ve seen what’s possible with Expression Blend’s more designer-friendly editor, let’s take a look at the same Silverlight project in Visual Studio 2010.

Silverlight Projects

The Silverlight runtime for WP7 supports some impressive media types with many different audio and video codecs, vector graphics, bitmap graphics, and animation. That should trigger the perimeter alert of any game developer worth their salt! Silverlight brings some highly interactive input mechanisms to the Web, including accelerometer motion detection, multitouch input (for devices that support it),camera, microphone input, and various phone-type features (like accessing an address book and dialing).

Making quick changes to the page is easy with Expression Blend.
FIGURE 2.5 Making quick changes to the page is easy with Expression Blend.

To find out whether your preferred web browser supports Silverlight, visit the installer web page at http://www.microsoft.com/getsilverlight/get-started/install.

The Visual Studio 2010 project templates specific to Silverlight are highlighted in bold in the list below. These are the same project templates shown in Expression Blend!

  • Windows Phone Application (Visual C#)
  • Windows Phone Databound Application (Visual C#)
  • Windows Phone Class Library (Visual C#)
  • Windows Phone Panorama Application (Visual C#)
  • Windows Phone Pivot Application (Visual C#)
  • Windows Phone Game (4.0) (Visual C#)
  • Windows Phone Game Library (4.0) (Visual C#)
  • Windows Game (4.0) (Visual C#)
  • Windows Game Library (4.0) (Visual C#)
  • Xbox 360 Game (4.0) (Visual C#)
  • Xbox 360 Game Library (4.0) (Visual C#)
  • Content Pipeline Extension Library (4.0)
  • Empty Content Project (4.0) (Visual C#)

Let’s create a quick project in Visual Studio in order to compare it with Expression Blend. You’ll note right away that it is not the same rich design environment, but is more programmer oriented.

Comparing Visual Studio with Expression Blend

Let’s create a new project in Visual C# 2010 in order to compare it with Expression Blend. Follow these steps:

  1. Open the New Project dialog with File, New Project.
  2. Next, in the New Project dialog, choose the target folder for the project and type in a project name, as shown in Figure 2.6.

    Creating a new Silverlight project in Visual C# 2010 Express.
    FIGURE 2.6 Creating a new Silverlight project in Visual C# 2010 Express.
  3. Click the OK button to generate the new project shown in the figure. Not very user-friendly, is it? First of all, double-clicking a label does not make it editable, among other limitations (compared to Expression Blend). Where are the control properties? Oh, yes, in the Properties window in Visual Studio. See Figure 2.7. This is also very data-centric, which programmers love and designers loathe. The view on the left is how the page appears on the device (or emulator); the view on the right is the HTML-like source code behind the page, which can be edited.
  4. Bring up the Properties window (if not already visible) by using the View menu. Select a control on the page, such as the application title. Scroll down in the Properties to the Text property, where you can change the label’s text, as shown in Figure 2.8. Play around with the various properties to change the horizontal alignment, the color of the text, and so on. Open the Toolbox (located on the left side of Visual Studio) to gain access to new controls such as the Ellipse control shown here.
    The new Silverlight project has been created.
    FIGURE 2.7 The new Silverlight project has been created.

    Adding content to the Silverlight page.
    FIGURE 2.8 Adding content to the Silverlight page.

XNA Game Studio

XNA Game Studio 4.0 was released in the fall of 2010. (From now on, let’s just shorten this to “XNA” or “XNA 4.0”, even though “Game Studio” is the name of the SDK, and “XNA” is the overall product name.) XNA 4.0 saw several new improvements to the graphics system, but due to the hardware of the Xbox 360, XNA is still based on Direct3D 9 (not the newer versions, Direct3D 10 or 11). This is actually very good news for a beginner, since Direct3D 9 is much easier to learn than 10 or 11. Although XNA abstracts the C++-based DirectX libraries into the C#-based XNA Framework, there is still much DirectX-ish code that you have to know in order to build a capable graphics engine in XNA. While XNA 4.0 added WP7 support, it simultaneously dropped support for Zune (the portable multimedia and music player).

I have a Zune HD, and it’s a nice device! It can play 720p HD movies and even export them to an HDTV via an adapter and HDMI cable. It plays music well too. But, like many consumers, I just did not have much incentive to go online and download games for the Zune. This is, of course, purely a subjective matter of opinion, but it’s disappointing for game developers who put effort into making games for Zune. Fortunately, the code base is largely the same (thanks to XNA and C#), so those Zune games can be easily ported to WP7 now.

Rendering states, enumerations, return values, and so forth are the same in XNA as they are in Direct3D, so it could be helpful to study a Direct3D book to improve your skills as an XNA programmer!

The project templates for Windows Phone might surprise you—there are only two! We can build a Windows Phone game or a game library. All the other templates are related to the other platforms supported by XNA.

  • Windows Phone Application (Visual C#)
  • Windows Phone Databound Application (Visual C#)
  • Windows Phone Class Library (Visual C#)
  • Windows Phone Panorama Application (Visual C#)
  • Windows Phone Pivot Application (Visual C#)
  • Windows Phone Game (4.0) (Visual C#)
  • Windows Phone Game Library (4.0) (Visual C#)
  • Windows Game (4.0) (Visual C#)
  • Windows Game Library (4.0) (Visual C#)
  • Xbox 360 Game (4.0) (Visual C#)
  • Xbox 360 Game Library (4.0) (Visual C#)
  • Content Pipeline Extension Library (4.0)
  • Empty Content Project (4.0) (Visual C#)

Let’s build a quick XNA project for Windows Phone to see what it looks like. We’ll definitely be doing a lot of this in upcoming chapters since XNA is our primary focus (the coverage of Silverlight was only for the curious—grab a full-blown Silverlight or Expression Blend book for more complete and in-depth coverage.

Creating Your First XNA 4.0 Project

Let’s create a new XNA 4.0 project in Visual C# 2010, so we can use this as a comparison with the previous project created with Expression Blend. Follow these steps:

  1. Create a new project. We’ll be basing these tutorials around Visual Studio 2010 Express for Windows Phone. The processes will be similar to using the Professional version, but you will see many more project templates in the New Project dialog. Open the File menu and choose New Project. The New Project dialog is shown in Figure 2.9.

    Creating a new XNA 4.0 project.
    FIGURE 2.9 Creating a new XNA 4.0 project.
  2. The new project has been created. Note, from Figure 2.10, the code that has been automatically generated for the XNA project. If you have ever worked with XNA before, this will be no surprise—the code looks exactly like the generated code for Windows and Xbox 360 projects!

    The new XNA 4.0 project has been created.
    FIGURE 2.10 The new XNA 4.0 project has been created.
  3. Run the project with Build, Run, or by pressing F5. The emulator will come up, as shown in Figure 2.11. Doesn’t look like much—just a blue screen! That’s exactly what we want to see, because we haven’t written any game code yet.
  4. Add a SpriteFont to the Content project. Right-click the content project, called XNA ExampleContent(Content) in the Solution Explorer. Choose Add, New Item, as shown in Figure 2.12.
    Running the XNA project in the Windows Phone emulator.
    FIGURE 2.11 Running the XNA project in the Windows Phone emulator.

    Adding a new item to the content project.
    FIGURE 2.12 Adding a new item to the content project.
  5. In the Add Item dialog, choose the Sprite Font item from the list, as shown in Figure 2.13, and leave the filename as SpriteFont1.spritefont.

    Adding a new SpriteFont content item to the project.
    FIGURE 2.13 Adding a new SpriteFont content item to the project.
  6. Create the font variable. The comments in the code listing have been removed to make the code easier to read. We’ll dig into the purpose of all this code in the next hour, so don’t be concerned with understanding all the code yet. Type in the two new bold lines of code shown here to add the font variable.
    [code]
    public class Game1 : Microsoft.Xna.Framework.Game
    {
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;
    //new font variable
    SpriteFont font;
    public Game1()
    {
    graphics = new GraphicsDeviceManager(this);
    Content.RootDirectory = “Content”;
    TargetElapsedTime = TimeSpan.FromTicks(333333);
    }
    [/code]
  7. Load the font. Enter the two new lines shown in bold in the LoadContent method.
    [code]
    protected override void Initialize()
    {
    base.Initialize();
    }
    protected override void LoadContent()
    {
    spriteBatch = new SpriteBatch(GraphicsDevice);
    //load the font
    font = Content.Load<SpriteFont>(“SpriteFont1”);
    }
    protected override void UnloadContent()
    {
    }
    [/code]
  8. Print a message on the screen. Using the SpriteBatch and SpriteFont objects, we can print any text message. This is done from the Draw method—add the code highlighted in bold.
    [code]
    protected override void Update(GameTime gameTime)
    {
    if (GamePad.GetState(PlayerIndex.One).Buttons.Back ==
    ButtonState.Pressed)
    this.Exit();
    base.Update(gameTime);
    }
    protected override void Draw(GameTime gameTime)
    {
    GraphicsDevice.Clear(Color.CornflowerBlue);
    //print a message
    spriteBatch.Begin();
    string text = “HELLO FROM XNA!”;
    Vector2 pos = font.MeasureString(text);
    spriteBatch.DrawString(font, text, pos, Color.White);
    spriteBatch.End();
    base.Draw(gameTime);
    }
    }
    [/code]
  9. Run the program using Debug, Start Debugging, or by pressing F5. The program will come up in the emulator, shown in Figure 2.14. Now there’s just one big problem: The font is too small, and the screen needs to be rotated to landscape mode so we can read it!
  10. Click the emulator window to cause the little control menu to appear at the upper right. There are two icons that will rotate the window left or right, allowing us to switch from portrait to landscape mode. All XNA projects will default to portrait mode by default. Landscape mode is shown in Figure 2.15.
    The text message is displayed in the emulator— sideways!
    FIGURE 2.14 The text message is displayed in the emulator— sideways!

    Rotating the emulator window to landscape mode for XNA projects.
    FIGURE 2.15 Rotating the emulator window to landscape mode for XNA projects.
  11. Enlarge the font. We’re almost done; there’s just one final thing I want to show you how to do here. Open the font file you created, SpriteFont1. spritefont. Change the size value from 14 to 36. Now rerun the project by pressing F5. The new, large font is shown in Figure 2.16.

    Enlarging the font to make it more readable.
    FIGURE 2.16 Enlarging the font to make it more readable.

XNA or Silverlight: What’s the Verdict?

We have now seen two projects developed with the two different, and somewhat competing tools: XNA and Silverlight. Which should we choose? This is really a matter of preference when it comes to developing a game. Although XNA is far more capable due to its rendering capabilities, Silverlight can be used to make a game as well, with form-based control programming. For portable, touchscreen applications, it’s a given: Silverlight. But for serious game development, XNA is the only serious option.

We covered quite a bit of information regarding Visual Studio 2010, the project templates available for Windows Phone, and the value-added tool Expression Blend. A sample project was presented using Expression Blend with a corresponding Silverlight project in Visual Studio, as well as an XNA project. We’re off to a good start and already writing quite a bit of code! In the next hour, you will create your first Windows Phone game.

Making Games for Windows Phone 7

Getting Started with Windows Phone 7

There are two ways we can develop games for Windows Phone 7: Silverlight and XNA Game Studio. Although Silverlight does have basic graphics capabilities, those capabilities are provided to support applications and are not ideally suited for games. XNA, on the other hand, was developed specifically for game development!

Before learning all about XNA Game Studio 4.0, Visual C# 2010, projects, configurations, Xbox Live, App Hub, and other great things that will interest a game developer, we need to first understand this new platform. Windows Phone 7, which we might call WP7 for short, is an operating system for smartphone devices.

In “the old days,” if you knew how to turn on a computer, you were called a “computer geek.” It didn’t really matter if you knew how to do anything with a computer; it was just assumed by many (especially in the older generations) that turning it on required knowledge of the black arts in electronics wizardry. That seems to be the case with most new technology, which people will tend to resist and perhaps even fear to a certain degree. When cars were first invented at the dawn of the automobile industry, people who drove around in a “horseless carriage” were considered snobbish, among the wealthy class—that is, until Henry Ford built a car that just about anyone could afford to buy. Not only did most people not have a computer in the early days, but most people at the time did not even begin to know how to go about buying one.

I’m speaking in terms of the time period around the mid- to late-1970s, at the dawn of the personal computer (PC) age. At that time, PCs were few and far between, and a kid who owned a Commodore PET, a Tandy TRS-80, or an Apple was a rare and lucky kid indeed! Most big businesses used big mainframe computers to do the most time-consuming tasks of any business—accounting, payroll, and taxes. But even at this time period, most white-collar employees who worked in an office did not have a PC. Imagine that! It’s unheard-of today! Today, the first thing a new employee must have is a cubicle or an office with a PC. And, not just that, but a networked PC with Internet access.

Windows Phone 7 as a Game Platform?

There was a time not too many years ago when just having a PC was enough to do your work—programming, software engineering, computer-aided design (CAD), word processing, accounting. Even in the 1980s, it was rare for every employee to have a PC at his or her desk, and even more rare for families to have a PC in their homes. A lot of kids might have had a Nintendo Entertainment System (NES) or Sega Master System (SMS) or the older Atari 2600, all of which used cartridge-based games. A step up from these video game systems were the true PCs of the time, such as the Apple II, Commodore 64, Amiga, Atari 400/800, and Atari ST. No computer enthusiasts at the time used an IBM PC at home! MS-DOS was a terrible operating system compared to the other, more user-friendly ones. If you wanted to do programming, you would naturally gravitate to the consumer PCs, not the business-oriented IBM PC. Now, at the time, the Apple Macintosh was pretty expensive and the ordinary kid would prefer an Apple II, but that was the start of the Mac, back in the 1980s (although it has been completely redesigned several times before reaching the modern OS X).

Well, today the world sure is a different place. If we just ignore how powerful computers are today, just look at all the hand-held systems—they’re everywhere! The Nintendo DS family and the Sony PlayStation Portable (PSP) family are the two leading competitors of hand-held video game systems, and they can do almost anything that their big brothers (Nintendo Wii and Sony PS3) can do, including online play. These things are everywhere! You can’t walk through a store or a mall without seeing kids carrying some sort of mobile video game system with them, not to mention phones. And it’s not just kids, but adults have their toys too, like Apple iPhone, iPod, and iPad, for which some really great games are available! One of my favorites is Plants vs Zombies by PopCap Games. You can also get the game for Xbox 360, Mac, Windows, and Nintendo DS. And you know what? Some popular games are starting to come out for Windows Phone 7 because it’s fairly easy to port an Xbox 360 game to Windows Phone 7.

So what is Windows Phone 7 all about? Obviously, since you’re reading this book, you are interested in programming games for the device. That goes without saying, but what is development for this platform really like? What’s it all about? We have to ask ourselves these questions because developing a game that you want to be taken seriously requires a pretty big investment of time, if not money. Most likely, anyone looking at Windows Phone 7 for game development is already experienced with XNA Game Studio. If you have never used this development tool, the next hour will be helpful because we’ll be creating projects and working with Visual C# quite a bit. I’ll assume that you might not have any experience with Visual Studio, but I do not want to annoy experienced developers, so bear with me a bit while we cover the basics such as these!

History of the Platform

Windows Phone 7 follows a long history of mobile devices from Microsoft, dating clear back to the Pocket PC in 2000. Pocket PC competed directly with the market leader of the time, Palm. The Palm Pilot was arguably the progenitor of all handsized mobile computers today, including cellphones.

Interestingly enough, I would not consider Apple’s iPhone as an evolutionary leap beyond Palm Pilot—ignoring the many devices that have entered the market in the intervening years of the past decade. The iPhone does not follow in the lineage of “mobile computer” dating back to the Palm Pilot and Pocket PC because it was derived from Apple’s wildly successful iPod. The iPod should have been invented by Sony, the company responsible for the “Walkman” generation of portable music players. Everyone in the 1980s and early 1990s owned a “Walkman,” regardless of the brand, in the same vein that everyone has played with a “Frisbee,” despite these being brand names with competing companies making similar products. We Americans, due to targeted advertising, come to associate whole industries with a single product name, merely out of habit.

At any rate, you might have heard the term “podcast.” The term is rather generalized today to mean audio streamed or recorded in digital form for playback on a digital media player. But the concept was invented by Apple for the iPod and iTunes (including iTunes University), which now work with video files as well as audio files. While everyone was caught up in the Napster lawsuits, Apple was busy developing iTunes and began selling music in a revolutionary new way: per track instead of per album. Have you ever heard a catchy new song on the radio and wanted to buy it for your iPod, Microsoft Zune, Creative Zen, or similar media player? Well, in the past decade, you would buy the whole CD and then rip the tracks into MP3 with software such as Windows Media Player or Winamp. This point is debatable, but I would argue that Apple iTunes proved that digital music sales can be a commercial success, highly profitable both for the recording artists and for the service provider (iTunes). Amazon is probably the second case example that proves this is now a commercially successful way to sell music.

The point is, iPod was so successful that it evolved into the iPhone and iPad, and competing companies have been trying to keep up with Apple in both of these markets now for years! The iPod and its relatives are insanely great, which is why everyone wants one. More than a fashion statement, Apple understood what the consumer wanted and made it for them. What did customers want? Not a do-everything badly device, but a do-the-most-important-thing great device. In contrast, many companies hire “experts” to conduct consumer studies, and then spend millions trying to convince customers that they really want and need that product. This might be one good way to break into a relatively unknown market or to adjust the feature set of a product according to consumer interest. But the situation Apple finds itself in today is enviable, and with that comes emulation.

The previous iteration of Windows Mobile was called Windows Phone 6.5, and over a dozen hardware manufacturers and networks supported it, from Acer to HP to Samsung. Prior to that, Windows Phone 5 revolutionized the platform with a GPU (graphics processing unit) for 3D rendering.

The current Windows Phone 7’s operating system traces its roots directly back to the original Pocket PC operating system released in 2000. Pocket PCs came with a stylus, much like the one used on a Nintendo DS. This allows for precise input coordinates, necessary for apps like a spreadsheet (a portable version of Excel called Pocket Excel was available). However, stylus input can be tedious in today’s hustle-and-bustle environment, where it is more convenient to use a thumb to do things on the device’s touchscreen. Who wants to fish out a stylus just to tap a silly pop-up button (which Microsoft developers are notoriously fond of) when a thumb or another finger will do the trick?

The online capabilities of the Sega Dreamcast video game console were made possible thanks to Windows CE. If you look at the front of the Dreamcast case, you will find a Windows CE logo.

To get technical, Windows Phone 7 is based on the Windows Mobile operating system, a new name for the classic Windows CE operating system. Windows CE goes back quite a few years. “Pocket PC” was a marketing name for Windows CE 3.1. Developers at the time used Microsoft eMbedded Visual Tools 3.0 (see Figure 1.1) to develop for Windows CE 3.1. This was a modified version of Visual Studio 6 for Windows CE that was actually a remarkable development environment! It was stable, fully featured, and free! This might be considered an early predecessor of the Express Editions now made available free by Microsoft. At the time, there were many Pocket PC models available, but the most notable ones were from Casio, HP, Dell, and Compaq.

FIGURE 1.1 Microsoft eMbedded Visual C++ 3.0.
FIGURE 1.1 Microsoft eMbedded Visual C++ 3.0.

Microsoft supported game development on the Pocket PC (Windows CE 3.1) by providing a low-level library called the Game API. It was nowhere near as powerful as DirectX for rendering; but neither was the Game API at the slower level of the Windows GDI (graphics device interface). No, the Game API did give access to the actual bits of the video memory, making it possible to write a low-level blitter (a term derived from the “bit-block transfer” form of memory copying). Many developers worked on sprite renderers and game libraries using the Game API, and a book was published on the subject—Pocket PC Game Programming: Using the Windows CE Game API, by Prima-Tech—in 2001. Some copies are still floating around if you’re curious about “the early days” and the predecessor of WP7. At the time, developers had their choice of eMbedded Visual Basic or eMbedded Visual C++, but today we’re developing games for WP7 using XNA and C#. In that 2001 book is a rudimentary game library surrounding WinMain() and the other Windows core code necessary when working in C++, as well as integrated Game API built into a series of classes.

I created one published game using the library from that early book, an indie game called Perfect Match, shown in Figure 1.2. It was sold on mobile sites such as www. Handango.com. Since I lost contact with the artist who did all the renderings, the game could not be updated or ported to any newer systems. By the way, the screen resolution was 240×320 in portrait orientation, and most games were designed to be played this way; but you’ll note that many WP7 games require the player to tilt the device sideways (landscape orientation). This is something that was not common back in the Pocket PC days, but it makes sense now.

FIGURE 1.2 Perfect Match, a Pocket PC 2000 game.

Another example from the time period is the final sample game in the book, a multiplayer game called Pocket Air Hockey, shown in Figure 1.3. This was a quick game, but even now, looking back on it, I think the chat keypad and networking code were quite good for a book example. I used the Windows Sockets (winsock) library with threading. To develop the game, I had two Pocket PCs (a Casio Cassiopeia and an HP Jornada) each equipped with a Hawking CF LAN card plugged into the top expansion port with blue CAT5 network cables going into each one. Can you imagine that? (There were also 802.11b Wi-Fi cards available for the Compact- Flash adapter port.) I just don’t think anyone was really into developing multiplayer games for this platform at the time.

FIGURE 1.3 Pocket Air Hockey, a networked multiplayer game.
FIGURE 1.3 Pocket Air Hockey, a networked multiplayer game.

There was no single processor standard for the original Pocket PC 2000 devices, but three came to be used: Hitachi SH-3, NEC VR MIPS, and StrongARM. The ARM processor would become the single standard for Pocket PC 2002. The reason there have been so many releases in recent years, compared to the past, without significant updates to the core operating system (Windows CE) is that there’s a need to keep up with the aggressive cellphone market’s demand for change, even when change is not entirely necessary. When a company releases some trivial new feature in one of its phones, all competitors must come up with a compelling reason for customers to choose their phone instead. The carrier networks (T-Mobile, AT&T, and Verizon, primarily) also push hard for new devices and plans to maintain their customers and attract new customers. So, Windows Mobile 6 might not even be recognizable between 2007 and 2009, but the changes are primarily cosmetic, but also have to do with user input and application support. This market has been chaotic, to say the least! Table 1.1 is a historical list of releases for the platform.

History of Windows Mobile
TABLE 1.1 History of Windows Mobile
History of Windows Mobile
TABLE 1.1 History of Windows Mobile

Windows Phone 7 was planned for release in 2009 with a core based on Windows CE 5.0—a core dating back to 2005. The core was just too old, so development failed. At that point, a stopgap product was released (Windows Phone 6.5) while Windows Phone 7 went back to the drawing board. The Windows Mobile team ended up rebuilding the new platform from scratch around the new Windows CE 6.0 core for release the following year (2010).

Hardware Specifications

What we have today in the WP7, a completely new operating system built from the ground up around the Windows CE 6.0 core, is a modern touch-enabled architecture with no resemblance to the Windows desktop computer operating system. It took many years, but Microsoft finally perfected the platform! No longer must mobile users tap with a stylus. A sample phone built by Samsung and connected to the AT&T network is shown in Figure 1.4. WP7 competes directly with two other smartphones in the industry today: Apple iPhone and Google Android. Apple is a closed architecture, meaning only Apple builds iPhone devices. WP7 and Android, on the other hand, are not so much mobile devices as they are operating systems. That is why there are many devices available in the Android and WP7 format—but there is only one iPhone. From a developer’s point of view, this openness makes life more difficult. Android, for instance, may be too open, with many different screen sizes and hardware specs. Developing a game for iPhone? That’s a piece of cake, as far as specifications go, because there is only one (although, admittedly, adjustments to the settings are required for iPad due to its larger screen resolution).

Table 1.2 shows the common hardware specifications among most of the models available at the time of this writing. The most notable thing about the specifications is that they now follow a basic standard across all manufacturers. Apple has proven that extreme openness and flexibility are not always desirable traits in mobile hardware. One of the difficulties facing Android developers today is the need to support many different hardware devices in a single code base. Windows Mobile developers had to deal with a similar problem in Windows Phone 6.4 and earlier versions, but as you can see, WP7 has a much simpler subset of hardware specifications. This is a good thing for developers, greatly simplifying the code, allowing developers to focus on game design and gameplay rather than hardware idiosyncrasies among the different makes and models.

A Windows Phone 7 device built by Samsung.
FIGURE 1.4 A Windows Phone 7 device built by Samsung.
Windows Phone 7 Hardware Specifications
TABLE 1.2 Windows Phone 7 Hardware Specifications

WP7 is an awesome integration of many technologies that have evolved over the years, beginning with the early Windows CE and Pocket PC devices, to the modern, powerful smartphone of today with advanced 3D rendering capabilities that truly bring cutting-edge gaming into the palm of your hand.

Windows Phone Performance Optimization, Fast! to Faster!

Optimizing your game’s performance

Games belong to a class of real-time software. This means that they are not only expected to produce the correct result, but they must also complete this within a fixed time window. In general, game developers shoot for a minimum of displaying 30 frames per second in order to produce smooth, glitch-free animations; and most prefer 60 frames per second. This means that all of the game calculations getting the player input, implementing enemy AI, moving objects, collision detection and handling, and drawing each frame must be completed within 16.7 milliseconds! When you consider that most modern video games have hundreds, or even thousands, of objects that have to be updated and drawn within that time period, it is no wonder that programmers feel they have to optimize every line of code.

However, many XNA programmers are not familiar with the tools and methods for determining when, where, how, or even if, they should optimize their code. The point of this recipe is to help you answer these questions.

Getting ready

The following section will help you to optimize your game’s performances

Design versus implementation

A common response by those who question, or even outright disagree, with the idea that optimizing the code early is a bad idea, is to point out that it is far easier to change software early in its lifecycle than after it has been written. That is, of course, very true. That is why it is important to understand the difference between the design optimization and implementation optimization.

While designing a game (or any software), you must take into account the size and complexity of your game, and select the correct data structures and algorithms that can support it. A simple 2D shooter or a platformer with no more than a hundred objects interacting at any given time can probably get away with a brute force approach for handling movements and collisions. Maintaining a simple list or an array of objects and iterating through it each frame will most likely work fine, and will be very simple to implement and debug.

However, a more complex game world, with perhaps thousands of active objects, will need an efficient method of partitioning the game space to minimize the number of object interaction tests in each frame. Similarly, games requiring detailed enemy AI will need to rely on algorithms that can produce “intelligent” actions as quickly as possible.

There are many resources available that discuss game programming algorithms. Some of them are as follows:

  • The use of quadtrees and octrees for partitioning the game world to minimize collision detection tests
  • The minimax algorithm with alpha-beta pruning for efficiently finding the “best” move in two player strategy games (please check the wiki link for more information at http://en.wikipedia.org/wiki/Alpha-beta_pruning)
  • The A* algorithm for efficient path finding (for more detail about the A* algorithm, please check the wiki link at http://en.wikipedia.org/wiki/A*_search_ algorithm)

The selection of appropriate data structures and algorithms during the design phase has a far greater impact on the eventual performance of your game than any implementation optimization you will make, as your algorithms determine the maximum number of operations your game will have to perform during each frame.

In order to demonstrate this point, imagine that for your first game you write a simple 2D shooter that relies on a brute force approach to collision detection. In every frame, you simply test every active object against every other active object to see if they intersect. As you decide to have only a limited number of enemies active at a time, it works well and easily runs at 60 frames per second.

With that experience under your belt, you now want to write a second game that is far more ambitious. This time you decide to write a Zelda-like adventure game with a large scrolling game board and hundreds of objects moving around it simultaneously. (The Legend of Zelda, an NDS game from Nintendo. You can find out more about this game at: http:// en.wikipedia.org/wiki/The_Legend_of_Zelda.) Using your existing code as a starting point, you get well into the game’s implementation before you discover that the brute force approach that worked very well in your simple game does not work so well in this new game. In fact, you may be measuring screen draws in seconds per frame instead of frames per second!

The reason is that, comparing every object against every other object is what is known as an O(n2) algorithm (for more information on estimating the algorithm time complexity, please see the classic book Introduction to Algorithm second edition, http://www.amazon. com/Introduction-Algorithms-Thomas-H-Cormen/dp/0262033844). That is, the number of operations that have to be performed is related to the square of the number of objects on which you are operating. If you have 10 objects in your game, you only have to perform a hundred tests to see if there are any collisions. If you have a hundred objects, you have to perform ten thousand tests, which may still be possible on a modern PC if each test can be done quickly enough. However, if you have five hundred just five times as many as the last example you will have to perform 250,000 collision tests. Even if each test took only 67 microseconds, you would still be using the entire 16.7 milliseconds frame time (usually at 60 frames per second) just for collision detection. The point is that it does not matter how efficiently you implement that algorithm in a code, its performance will still devolve exponentially with the number of objects in your game, and will therefore be the single greatest limiting factor to the size of your game.

Game runs slow?

Ok, so your game is playable with most of the features you want to be implemented. However, when you test the application, you find that the animation runs like a robot, the character should run, but it is crawling. What is wrong there? You might say, it is about the compiler features, such as the foreach keyword, or ask whether you need to pass the matrices by reference, not by values.

You have two choices: stop there and take a step back or fix it, and start going into each method trying to figure out how to find your way around the problem on a case-by-case basis. Maybe you will even succeed and get the game back into the runnable state that you had it in hours earlier. Maybe you are even lucky enough to have not introduced yet more bugs into the process. However, in all likelihood, you have not fixed the problem and now you have code that does not run any better than when you started, but is harder to understand, harder to debug, and has kludges in it to get around problems that you introduced trying to fix the wrong problem. Your time will be much better spent finding out where your problems are before you try to fix them.

Measuring the running time

A prototype is just a simplified version of software (in this case, your game), that focuses on one particular aspect of it. Prototypes are often used as proofs of concept to show that the software will be able to work as expected. As prototypes don’t have to deal with all of the details that the final software will, they can be written quickly so that, if necessary, different approaches can be evaluated.

Prototypes are frequently used to evaluate user interfaces, so that customers can provide early feedback. This can be useful for game programming too, as if you can implement a working display and control scheme, you may be able to find out what works and doesn’t work before you get too far along in the actual implementation of the game. However, the use of prototypes that we are concerned with here is to determine whether an algorithm is fast enough for the game we want to write. To do that, we will want to benchmark it. Benchmarking is just the process of timing how long an algorithm takes to run.

How to do it…

Fortunately, the .NET framework makes benchmarking very easy by providing the System. Debug.Stopwatch class. The Stopwatch class provides a Start and a Stop method. It keeps track of the total number of clock ticks that occur between calls to Start and Stop. Even better, like a real stopwatch, it keeps a running count of ticks between successive calls to Start and Stop. You can find out how much time has passed by querying its ElapsedTicks or ElapsedMilliseconds properties. A Reset() method lets us reset Stopwatch back to zero.

Now, follow the steps to take advantage of the Stopwatch class:

  1. As a showcase, the following code gives you a general picture on how to use the Stopwatch class for time measuring:
    [code]
    public abstract class Sprite
    {
    public Vector2 Position { get; set; }
    public Color Color { get; set; }
    // Sprite’s collision rectangle in screen coordinates.
    public BoundingRectangle BoundingBox { get; }
    public Sprite(
    string imageName,
    BoundingRectangle boundingBox);
    public virtual void Initialize();
    public virtual void LoadGraphicsContent(
    ContentManager content);
    public virtual void Update(GameTime time);
    public virtual void Draw(SpriteBatch spriteBatch);
    // Tests for collision with another Sprite. If a
    // collision occurs, it calls the Collide method for
    // both Sprites. Returns true if images collide.
    public bool TestCollision(Sprite item);
    // Called when the TestCollision method detects a
    // collision with another Sprite.
    //
    protected virtual void Collide(
    BoundingRectangle overlap,
    Sprite item);
    }
    [/code]
  2. As it is an abstract, it is intended to be used as a parent to other Sprite classes that will implement its behavior, so we will create our own TestSprite class. TestSprite will generate a random starting position, directional movement vector, and speed (in pixels per second), as shown here:
    [code]
    public override void Initialize()
    {
    // Set starting position.
    Position =
    new Vector2(
    random.Next(screenWidth),
    random.Next(screenHeight));
    // Create a random movement vector.
    direction.X = (float)random.NextDouble() * 2 – 1;
    direction.Y = (float)random.NextDouble() * 2 – 1;
    direction.Normalize();
    // Determine random speed in pixels per second.
    speed = (float)random.NextDouble() * 300 + 150;
    }
    [/code]
  3. In each frame, the following code will update its position based on its movement direction, speed, and the amount of time that has elapsed. It will also test to see if it has hit the edge of the screen, and deflect away from it:
    [code]
    public override void Update(GameTime time)
    {
    // Reset color back to white.
    Color = Microsoft.Xna.Framework.Graphics.Color.White;
    // Calculate movement vector.
    Vector2 move =
    (float)time.ElapsedGameTime.TotalSeconds *
    speed * direction;
    // Determine new position.
    UpdatePosition(move);
    }
    private void UpdatePosition(Vector2 move)
    {
    Position += move;
    if ((BoundingBox.Left < 0) ||
    (BoundingBox.Right > screenWidth))
    {
    direction.X = -direction.X;
    Position -= new Vector2(move.X, 0);
    }
    if ((BoundingBox.Top < 0) ||
    (BoundingBox.Bottom > screenHeight))
    {
    direction.Y = -direction.Y;
    Position -= new Vector2(0, move.Y);
    }
    }
    [/code]
  4. We will talk more about collision testing next. For now, we will see what it takes to time just moving our TestSprite around the screen. Inside our game, we will create a TestSprite object and call its Initialize() and LoadGraphicsContent() methods at appropriate places. And we will create SpriteBatch for our game and pass it to Draw(). Now all we need is to use Stopwatch to time it in the Update() method. In order to do this, we will create a couple of helper methods that start and stop Stopwatch, and print the amount of time it takes for each update:
    [code]
    private Stopwatch updateTimer;
    private int updates = 0;
    private int framesPerSecond;
    private void StartTimer()
    {
    updateTimer.Start();
    }
    private void StopTimer()
    {
    updateTimer.Stop();
    updates++;
    // Show the results every five seconds.
    if (updates == 5 * framesPerSecond)
    {
    Debug.WriteLine(
    updates + ” updates took ” +
    updateTimer.ElapsedTicks + ” ticks (” +
    updateTimer.ElapsedMilliseconds +
    ” milliseconds).”);
    int msPerUpdate =
    (int)updateTimer.ElapsedMilliseconds / updates;
    Debug.WriteLine(
    “Each update took ” +
    msPerUpdate + ” milliseconds.”);
    // Reset stopwatch.
    updates = 0;
    updateTimer.Reset();
    }
    }
    [/code]
  5. By putting calls to StartTimer and StopTimer around the calls to our sprite’s Update() method, we will get a report of the average time each call takes:
    [code]
    300 updates took 34931 ticks (9 milliseconds).
    Each update took 0.03 milliseconds.
    300 updates took 24445 ticks (6 milliseconds).
    Each update took 0.02 milliseconds.
    300 updates took 23541 ticks (6 milliseconds).
    Each update took 0.02 milliseconds.
    300 updates took 23583 ticks (6 milliseconds).
    Each update took 0.02 milliseconds.
    300 updates took 23963 ticks (6 milliseconds).
    Each update took 0.02 milliseconds.
    [/code]

How it works…

In step 1, the Initialize(), LoadGraphicsContent(), Update(), and Draw() methods are the standard methods for Windows Phone 7 XNA Game Programming. Additionally, it provides properties for getting and setting the position and color. For collision detection, the Collide() method called by TestCollision() tests for collision with another Sprite BoundingBox values intersect.

In step 3, an actual game may want to determine the actual point of intersection so it could deflect away from that point more realistically. If you need that level of realism, you would probably want to go ahead and implement your strategy here, so you could time it. However, all we are trying to prototype here is a basic update time, so that this version is fine for our needs.

Note that the Update() method does not test for collisions. We don’t want individual sprite testing for collisions because to do so, our Sprite class would have to know about other game objects and we would be severely limiting our design options for collision testing. Any change to our collision-testing algorithm could, and likely would, affect our Sprite class. We want to avoid anything that limits future design changes, so we will give our Sprite class the ability to test for collisions, but require another part of our code to determine what objects should be tested.

In step 6, each call took on average of 20 microseconds (on my development laptop your results will vary). However, notice that the very first set of updates took almost one and a half times as long to run as the others. That is because the first time these methods are called, the JIT compiler compiles the code and our Stopwatch is timing that as well. It is also possible, as this is a fairly small amount of code that is being called repeatedly, that some or all of it may be fitting in the cache, which will increase the speed of later calls.

These show some of the problems with benchmarking code. Another problem is that we are adding some time by using Stopwatch itself. Thus, benchmark times for prototype code can be used as a general guide, but cannot be relied upon for exact values. In fact, exact values of the time it takes for functions to run are very hard to determine. Although intended only to describe quantum phenomena, a variation of the Heisenberg Uncertainty Principle is at play here: the act of measuring something affects the thing being measured.

There’s more…

Now let’s expand our prototype to help us determine whether we can get away with a brute force approach to collision detection.

First, let’s look at the collision handling code that I have already placed in the Collide method. Remember that this gets called, for both sprites, whenever the TestCollision() method determines a collision between two sprites. All it does is set the Sprite’s color to red:

[code]
protected override void Collide(
BoundingRectangle overlap,
Sprite item)
{
// Turn the sprite red to indicate collision.
Color = Color.Red;
}
[/code]

Let’s give this a test by replacing our single TestSprite with an array of TestSprites. Every place we referenced TestSprite in the original code, we now have to loop through the array to handle all of our TestSprites. In order to make this a little easier to manage, we will refactor our original sprite.Update() call in the Update() method into a new UpdateSprites() method that updates every sprite. We will add a new HandleCollisions() method to our game to test for collisions. Finally, we will change the Update() method, so that it only calls StartTimer and StopTimer around the call to HandleCollisions(). The relevant sections look like the following code:
[code]
private TestSprite[] sprites = new TestSprite[10];
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
{
this.Exit();
}
UpdateSprites(gameTime);
StartTimer();
HandleCollisions();
StopTimer();
base.Update(gameTime);
}
private void UpdateSprites(GameTime gameTime)
{
foreach (Sprite sprite in sprites)
{
sprite.Update(gameTime);
}
}
private void HandleCollisions()
{
// This is brute force approach
for (int i = 0; i < sprites.Length; i++)
{
for (int j = i + 1; j < sprites.Length; j++)
{
sprites[i].TestCollision(sprites[j]);
}
}
}
[/code]

Looking at that, you may wonder why I am not using foreach for the HandleCollisions call. It is simply because with foreach, we have no way of knowing what sprites we already tested. This algorithm tests every sprite against every other sprite exactly once.

What are the results? On my machine, with 10 sprites, I get the following:
[code]
300 updates took 48827 ticks (13 milliseconds).
Each update took 0.04333333 milliseconds.
300 updates took 42466 ticks (11 milliseconds).
Each update took 0.03666667 milliseconds.
300 updates took 42371 ticks (11 milliseconds).
Each update took 0.03666667 milliseconds.
300 updates took 43086 ticks (12 milliseconds).
Each update took 0.04 milliseconds.
300 updates took 43449 ticks (12 milliseconds).
Each update took 0.04 milliseconds.
[/code]

Wow! Handling collisions for 10 sprites takes only twice as long as it did just to move one sprite. How could that be? It is partly due to the overhead of using the Stopwatch class and making method calls, and partly due to the fact that we are measuring very fast operations. Obviously, the closer you get to the resolution of the underlying timer, the more error you get in trying to time things.

Before we go on, notice also that the impact of the JIT compiler during our first set of updates is significantly less. This shows how effective the JIT compilation is and why we don’t need to worry about it affecting the performance of our game. We may take a performance hit the first time a section of code is running, but it is relatively miniscule to our overall performance.

Now let’s see what happens when we increase the number of sprites to 100:

[code]
300 updates took 2079460 ticks (580 milliseconds).
Each update took 1.933333 milliseconds.
300 updates took 2156954 ticks (602 milliseconds).
Each update took 2.006667 milliseconds.
300 updates took 2138909 ticks (597 milliseconds).
Each update took 1.99 milliseconds.
300 updates took 2150696 ticks (600 milliseconds).
Each update took 2 milliseconds.
300 updates took 2169919 ticks (606 milliseconds).
Each update took 2.02 milliseconds.
[/code]

Whether you should be impressed or dismayed depends on how you want to use this collision-handling algorithm. On one hand, averaging 2 milliseconds per frame is still a miniscule part of our 16.7 millisecond frame timing. If you are not planning to have more than a hundred sprites or so, this algorithm will suit your needs perfectly. However, looking at the relative time difference per sprite gives a completely different perspective. It takes us 50 times as long to handle 10 times the number of sprites.

How about when the number is increased to 500? I urge you to run this code, so that you can see the results for yourself!

[code]
300 updates took 28266113 ticks (7896 milliseconds).
Each update took 26.32 milliseconds.
300 updates took 28179606 ticks (7872 milliseconds).
Each update took 26.24 milliseconds.
300 updates took 28291296 ticks (7903 milliseconds).
Each update took 26.34333 milliseconds.
300 updates took 28199114 ticks (7877 milliseconds).
Each update took 26.25667 milliseconds.
300 updates took 28182787 ticks (7873 milliseconds).
Each update took 26.24333 milliseconds.
[/code]

At this time there is no way to hide the dismay. The movement is clearly getting far less than our desired 60 frames per second! In fact, just the HandleCollisions() call alone is taking almost twice our allotted 16.7 milliseconds per frame. Multiplying the number of objects by 5 increased our time by 13! The times are not increasing exactly in quadric, due to overhead, but the rate of increase is clear.

Does this mean we should never consider this algorithm? Hopefully, at this point the answer is obvious. Many games can easily get away with only having an order of a hundred or so objects active at a time, which we have clearly shown can be handled easily. The fact that the algorithm is trivial to implement and maintain makes it a no-brainer for a large number of games.

On the other hand, if you know you will need to have hundreds of objects, you will need another solution. You have two options: optimize this algorithm, or find a new one. Anyone who is experienced with code optimization will see several obvious ways to make both the algorithm and its implementation more efficient.

For starters, most games don’t actually need to test every object against every other object. Taking the Space Invasion game as an example, I don’t need to test invaders for collision with other invaders. In fact, it is almost crazy to do so.

Another obvious optimization is that the Sprite class’s BoundingBox property is adding the sprite’s current screen position to its internal BoundingRectangle every time TestCollision is called, this despite the fact that the position changes only once or twice per frame. TestCollision, on the other hand, is called once for every other sprite in the game.

In addition, the Sprite’s TestCollision code is computing the actual intersection rectangle even though we are not using it here. We could easily save some time by not computing it. However, we give ourselves more flexibility by going ahead and doing it. Remember that this is supposed to be a generic Sprite class that can be used for many games.

These suggestions don’t even get into implementation optimizations, such as always passing our BoundingBoxes by reference instead of value; and providing direct access to member variables instead of accessing them through properties. These are exactly the types of optimizations suggested by many efficiency proponents in the XNA forums. However, these also make the code less readable, harder to debug, and harder to maintain.

As Space Invasion never has more than around 60 objects on the screen at a time, the unoptimized brute force approach works just fine. In addition, that is undoubtedly true for many other games as well. However, what if your game does need more than 100 collidable objects? Should you not make those optimizations so you can handle them?

The answer is… maybe. By making some of these optimizations, we can get this same brute force algorithm to handle 500 objects at a far more reasonable 6.4 milliseconds per frame.

[code]
300 updates took 6682522 ticks (1866 milliseconds).
Each update took 6.22 milliseconds.
300 updates took 7038462 ticks (1966 milliseconds).
Each update took 6.553333 milliseconds.
300 updates took 7023610 ticks (1962 milliseconds).
Each update took 6.54 milliseconds.
300 updates took 6718281 ticks (1876 milliseconds).
Each update took 6.253334 milliseconds.
300 updates took 7136208 ticks (1993 milliseconds).
Each update took 6.643333 milliseconds.
[/code]

That is an impressive improvement and shows how significantly performance can be optimized through these techniques. However, the disadvantages mentioned earlier less maintainable and less flexible code should not be ignored. In addition, even if you do these sorts of implementation optimizations, keep in mind that this algorithm will still degrade exponentially as you add more objects. You may be able to move up from 100 to 500 objects, but it won’t get you to 1000. At some point, you need to recognize that you need a different algorithm to efficiently handle more objects, such as the one that partitions your game space, like quad trees.

Finally, remember that 6.4 milliseconds is still 40 percent of your entire frame time. If you are maintaining on the order of a thousand or more objects at a time, other parts of your code are almost certainly also going to be difficult to manage at a reasonable frame rate. Is optimizing your collision detection the best use of your time? How do you know in advance which ones to optimize? Optimizing all of them as you go will surely take you longer to write, not to mention make your code more difficult to debug and maintain.

If benchmarking shows your algorithm has problems without implementation optimizations, you are probably better off with a different algorithm.

Using the EQATEC Profiler to profile your game’s running time

Profiling your game performance is a significant part of the whole game development process. No matter how efficient the used algorithms are, or how powerful the hardware is, you still need to get sufficiently accurate CPU running time charts for different functions calling in different hardware conditions. Choosing a good profiling tool will help you to find the hot spots which consume most CPU game resources, and lead you to create the most efficient optimization. For Windows Phone, EQATEC is a good choice and in this recipe, you will learn how to use the EQATEC Profiler to profile your Window Phone game.

Getting ready

You can download the EQATEC Profiler from the official company website located at the following URL:

[code]
http://www.eqatec.com/Profiler/
[/code]

The following screenshot shows what website looks like:

EQATEC Profiler from the official company

After clicking on the Download EQATEC Profiler, a new page will let you choose the profiler version; the free version is fine for our needs. After filling out some basic information, the website will send a URL for downloading the profiler to your e-mail address. When you have installed the downloaded profiler, you are ready for profiling your Windows Phone 7 game.

How to do it…

Carry out the following steps:

  1. Run the EQATEC Profiler through the Start menu or through the root directory where the profiler binary application is located. If the profiler runs correctly, you should get the following screen:
    EQATEC Profiler through the Start menu
  2. The Browse button lets you locate the root directory of your Windows Phone 7 XAP file for profiling. When the directory is set, you will choose the XAP file which will be listed in the list box under the App path textbox. The testing XAP file and source code can be found in the bundle file of this chapter. After that, you should click on the Browse button for building the profile description file that processed the number of methods in the designated application and some application metadata.
  3. Then, after selecting the application you want to profile, click on the Run button to start the profiling. When the Run button is clicked, a prompt will pop up asking you about the device to be used for profiling, Windows Phone 7 Device or Windows Phone 7 Emulator. In the example, we chose the emulator as shown in the following screenshot:
    Windows Phone 7 Device or Windows Phone 7 Emulator
  4. Under the Run tab, if you are sure the Windows Phone 7 application is ready, it is time for profiling. The window should look similar to the following screenshot:
    Run tab, if you are sure the Windows Phone 7
  5. Now, click on the yellow Run app button. The profiler will automatically start a Windows Phone 7 emulator and connect to the emulator. Next, it will install the profiled Windows Phone 7 XAP file on the emulator. When this step is done, profiler will start to track and profile the designated application. At this moment, if you want to know the actual time of every method in your application costs, you need to click on the Take snapshot button with a timer symbol under the information list box, and a new snapshot report which includes the running time of every method will be generated. Then, click on the yellow View button once you have chosen the report you want to review.
  6. In the snapshot view window, you will find how many milliseconds every method takes. The windows will look similar to the following screenshot:
    many milliseconds every method

How it works…

The time of every method is listed in the list box:

  • Initialize() method: 693 MS
  • LoadContent() method: 671 MS
  • Draw() method: 122 MS
  • DrawModel() method: 50 MS
  • Update() method: 43 MS

You can find more details in the Details of Individual methods panel. This panel will tell you the percentage of called method costs on time of the caller. In this example, the LoadContent() method consumes 671 MS which occupies 97percent of the Initialize() method total time.

Reducing the game contents’ loading time

As you know, most of the time, before playing a game, a screen for loading game contents will show up with a running progress bar. Without this, you may feel the game is stuck and not responding. If you know that the game is loading and can see its progress, you know that all you have to do is wait. Usually, no one wants to wait too long for playing games, however. It is wasting time and can cause frustration to the user. For better user experiences, the following sections will tell you how to reduce the loading time of game contents.

Making good loading decisions

Often, the first step in reducing loading times is to understand where the current greatest expenses are. Highlighting the frequency and timing of content loading is an effective way to evaluate and adjust loading times, as well as validate that the right content (no more and no less) is being loaded in a given scenario. Consider instrumenting the following:

  • The time required to load an asset; the System.Diagnostics.Stopwatch object can be used for this
  • The frequency with which each asset has been loaded over multiple game levels, across sessions, and so on
  • The frequency with which each asset is freed
  • The average lifetime

Using the XNA content pipeline to reduce file size

Compressing the game contents into an XNB file will make a great file size reduction in building time.

For the XNA framework, assets are shared between PC, Xbox, and Windows Phone 7 platforms, and you can reuse the textures, models, and so on. If a texture is consistently scaled down for display on a Windows Phone 7, consider performing that scaling offline, rather than taking the processing penalty bandwidth and memory overhead when loading the content.

Developers may also want to exploit other texture types, such as PNG, where doing so would not contribute to already compressed assets. For sparse textures, PNG on Windows Phone will typically demonstrate superior compression to a DXT-compressed content that is brought through the XNA content pipeline. In order to use other texture types, the source files must be copied to the output directory and not compiled in the content pipeline.

Note that, while DXT-compressed assets can be used natively by Windows Phone 7 GPUs, many formats including PNG need to be expanded at runtime to a raw format of 32 bits per pixel. This expansion can lead to increased memory overhead compared to DXT compression.

In order to balance the runtime memory footprint of DXT with the loading time footprint of more aggressive compression formats, developers may choose to apply custom compression and runtime decompression to the DXT content (as built by the XNA pipeline into .xnb files), which can lead to a significant reduction in loading times. Developers should balance the loading time considerations with CPU requirements to decode their custom-encoded content, as well as with memory requirements to handle and manipulate the decompressed data. The offline custom compression and runtime title-managed decompression of the DXT content can offer a good balance of reduced size (and thus, reduced loading time) without large runtime memory costs.

Developers can also pack multiple images into a single texture, as demonstrated by the content processor in the spritesheet. We have already discussed in Chapter 4, Heads Up Display (HUD)—Your Phone Game User Interface, that spritesheets avoid DXT power-of-two restrictions imposed by the XNA content processor, and optimize the file loading (replacing many small files with one larger one).

In the realm of sound, if native audio assets from a console title are 48 kHz, consider down sampling them to 44.1 kHz (prior to applying the XNA pipeline’s own compression) for use on the phone. This will realize an immediate 8 percent savings (approximately) on storage and reading bandwidth, as well as mild CPU savings for running at the native sampling rate of the Windows Phone device (44.1 kHz).

Beyond compression, decreasing loading times can focus on data organization that focuses on the efforts of loading the content that is needed to drive to an initial interactive state, rather than preparing all possible loaded data. This is particularly important in avoiding the watchdog timer; a title that loads data for too long prior to drawing to the screen risks being terminated by the system. Developers should also give similar attention to the in-game content loading. Remember that returning to gameplay from interruptions (SMS, phone, app purchase, and so on) invalidates all the previously loaded content.

Evaluating the asynchronous background loading

Even if the game takes a substantial set-up time, there are numerous techniques to getting the user into some kind of interactive state sooner. Anything from a simplified arcade-style loading screen to cut-scenes, trivia, “did you know” facts, and other low-CPU-impact techniques can be leveraged to help smooth the setup and transition from loading to gameplay.

Loading to an initial menu state or a cut-scene, and then continuing to load additional assets in the background would seem to be appropriate strategies for masking loading times from the consumer. However, LoadContent() performs byte copies of each loaded texture asset that uses the XNA content pipeline, generating garbage. Moreover, LoadContent(), overall, will trigger the garbage collection at each megabyte of loaded data. Depending on the actual interactivity of foreground scenes, the potential CPU cost taken by garbage collection may be acceptable; playback of pre-rendered video cut-scenes takes advantage of purpose-built hardware, so the CPU utilization is typically negligible. Similarly, static or intermittently animated menu systems would likely have more success here than attempting to generate the CPU-intensive content rendered in-engine during the background loading.

Considering the custom serialization

Microsoft’s .NET framework provides an easy to use method for serializing data onto disks, using types present in the System.Xml.Serialization namespace. Simplicity always comes with tradeoffs, however; in this case, the tradeoff is the file size. The default serialization schema is verbose. The behavior of the XmlSerializer is trivially easy to change, however, and can result in significant savings in file sizes.

As an example, let’s consider the following class definition:

[code]
public class TestClass
{
public int count;
public float size;
public bool enabled;
public string
LongNameOfAMinorFieldThatDoesntNeedALongNameInTheFile = “test”;
}
[/code]

The preceding class definition, when serialized with the default XmlSerializer, produces the following XML:

[code]
<?xml version=”1.0″?>
<TestClass xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd=”http://www.w3.org/2001/XMLSchema”>
<count>0</count>
<size>0</size>
<enabled>false</enabled>
<LongNameOfAMinorFieldThatDoesntNeedALongNameInTheFile>test
</LongNameOfAMinorFieldThatDoesntNeedALongNameInTheFile>
</TestClass>
[/code]

The default behavior of XmlSerializer is to treat each public field or property as an XML element. This generates quite a bit of extra data in the file; this XML file uses 332 bytes on the disk to serialize four fields. With a few simple changes, we can get significantly smaller files from XmlSerializer. Consider the following class declaration:

[code]
public class TestClass2
{
[XmlAttribute(AttributeName=”count”)]
public int count;
[XmlAttribute(AttributeName=”size”)]
public float size;
[XmlAttribute(AttributeName=”enable”)]
public bool enabled;
[XmlAttribute(AttributeName = “longName”)]
public string
LongNameOfAMinorFieldThatDoesntNeedALongNameInTheFile = “test”;
}
[/code]

With XmlAttribute added to properties, the XmlSerializer treats the field as attributes rather than elements, and gives the attributes alternative names. The resulting XML is the following:
[code]
<?xml version=”1.0″?>
<TestClass2 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:xsd=”http://www.w3.org/2001/XMLSchema” count =”0″ size =”0″
enable =”false” longName =”test” />
[/code]

The serialized file has significantly less wasted text. The file size also shrank to 167 bytes. This is a saving of roughly 50 percent, and a more reasonable file size to serialize four fields. Modifying your serialization code to prefer the XML attributes to XML elements will often result in similar savings. Even if you don’t perform renaming, as we did in this example, you will generally get close to a 50 percent reduction, as every XmlElement has to have a closing tag, while attributes don’t.

Avoid using XmlAttribute for complex types, or for collections of types. The space savings are minimal in these cases, and the resulting file is considerably more difficult to read. For larger amounts of data, consider writing a custom binary serialization code. In all cases, ensure that you time any new code to confirm any realized performance gains over the default Serializer settings.

Improving game performance with garbage collection

Discussing the garbage collector (GC) that runs on Windows Phone 7 devices is helpful for the Windows Phone 7 game developer. Anyone who has programmed in XNA for Windows or Xbox 360 before knows the GC well.

Value types versus reference types

One of the first things you must understand is the difference between value types and reference types. Value types such as int, float, Vector3, Matrix, and struct (this includes nullable types; a nullable type such as BOOL is just a special struct) live on the stack. The GC does not care about the stack. Well, technically, it cares slightly, but only to the extent that the system begins to run low on memory, and you would have to be trying very hard to get enough items on the stack to cause the system to run low on memory. So don’t worry about calling “new Vector3()” or “Matrix.CreateTranslation()” in your methods that run regularly (such as Update and Draw) it is just a stack allocation and it won’t anger the GC.

Classes are an entirely different matter. Classes, arrays (including arrays of value types, for example, int[ ]), collections (List<>, Dictionary<>, and so on.), and strings (yes, strings) are all reference types and they live on the heap. The heap is the GC’s caring. It pays attention to everything that shows up on the heap and to everything that no longer has any business there, but is still hanging around.

Defining a true value checking method

Take a look at the following code listing:

[code]
void CheckForTrue(bool value)
{
string trueText = “The value is true.”;
string falseText = “The value is false.”;
if (value == true)
{
Console.WriteLine(trueText);
}
else
{
Console.WriteLine(falseText);
}
return;
}
[/code]

Every time this method runs, trueText and falseText will both be allocated on the heap and will “go out of scope” when the the method is run. In other words, “gone out of scope” simply means that there are no more references to an object. A string declared with const never goes out of scope, and thus does not matter to GC for all practical purposes. This is also true for any object declared as static readonly, as once it is created it exists forever. However, the same is not true for a normal static, though many might mistakenly assume so. A static object without the readonly keyword applied to it will generally exist for the life of a program. However, if it is ever set to null, then unless there is some other reference to it, it goes out of scope and is subject to garbage collection.

Technically, the GC runs for every 1 MB of heap allocation. Whenever the GC is running, it takes time to comb through the heap and destroy any objects that are no longer in scope. Depending on how many references you have and how complex nesting of objects is, this can take a bit of time. In XNA, the clock is on a fixed time-step by default and in Windows Phone 7, the default frame rate is 30 FPS. This means that there are 33.3333333 milliseconds available for Update() and Draw() methods to finish their CPU-side tasks. Draw prepares things on the CPU-side, then hands over the actual drawing to the GPU which, being a separate processor, does not usually affect the Update/Draw side of things, except for stalls, but those are beyond the scope of this book and most people will never run into them anyway. If they finish ahead of time, the CPU hangs out and waits until it is time to run Update() again. If not, then the system takes notice that it is running behind and will skip as many draws as necessary to catch back up.

This is where the GC comes in. Normally, your code will complete just fine within 33.33 milliseconds, thereby maintaining a nice even 30 FPS (if your code does not normally complete within that time, you will see serious constant performance problems that may even cause your game to crash after a little while if XNA gets so far behind that it throws up its hands and surrenders). However, when the GC runs, it eats into that time. If you have kept the heap nice and simple, the GC will run nice and fast and this likely won’t matter. However, keeping a simple heap that the GC can run through quickly is a difficult programming task that requires a lot of planning and/or rewriting, and even then is not fool proof (sometimes, you just have a lot of stuff on the heap in a complex game with many assets). A much simpler option assuming you can do it is to limit or even eliminate all allocations during gameplay. You will obviously be allocating heap memory when you first start the game (for example, when loading assets in the LoadContent() method), and you will be allocating memory when loading levels, if you have a game with levels and decide to load each one in an interstitial screen. You will also be allocating memory when changing game screens. However, a small stutter from a couple of dropped frames in between levels or while switching screens is not a big concern the player is not going to accidentally fall off a cliff or get hit by an enemy projectile or anything when those things are happening. In fact, sometimes it makes a lot of sense to intentionally trigger the GC right before the game is going to (re)start. Triggering the GC resets the 1 MB counter and can prevent situations where the counter is at .94 MB when the level begins, such that even a small number of minimal allocations that would otherwise be perfectly acceptable, can cause problems.

Therefore, the goal is to minimize heap allocations. How do we do that? Well, the biggest contributors are needlessly creating new objects in your Update or Draw cycle and boxing value types. First, a quick note on boxing; the simplest example of boxing is casting a value type like int or enum to object in order to pass it as a state. Boxing is a great feature of .NET, but not recommended for game programming because of the heap allocations that can trigger the GC. So keep an eye out for it and try not to do it.

Another big contributor is creating new reference types. Every new instance of an object causes a heap allocation and increases that counter ever so slightly. There are several coding practices that will help you to eliminate needless heap allocation and increase performance for your game.

Using StringBuilder for string operations

Make any strings that never change into const strings.

Where you need strings that change, consider using System.Text.StringBuilder (visit http://msdn.microsoft.com/en-us/library/system.text. stringbuilder.aspx for more information on StringBuilder). All XNA methods that take a string (for example, SpriteBatch.DrawString) will also take a StringBuilder object. Make sure to use one of the constructors which take a default capacity and set it to a value high enough to hold as many characters as you plan, plus a few extra for good measure. If the internal array is large, it will never have to resize itself, and thus will never generate any heap allocations after it is created!

Drawing integer in string without garbage

If you need to draw an int value, such as a score or the number of lives a player has, consider using the following block of code (thanks to Stephen Styrchak):

[code]
public static class SpriteBatchExtensions
{
private static string[] digits = { “0”, “1”, “2”, “3”, “4”, “5”,
“6”, “7”, “8”, “9” };
private static string[] charBuffer = new string[10];
private static float[] xposBuffer = new float[10];
private static readonly string minValue =
Int32.MinValue.ToString(CultureInfo.InvariantCulture);
// Extension method for SpriteBatch that draws an integer
// without allocating any memory. This function avoids garbage
// collections that are normally caused by calling
// Int32.ToString or String.Format. the equivalent of calling
// spriteFont.MeasureString on
// value.ToString(CultureInfo.InvariantCulture).
public static Vector2 DrawInt32(this SpriteBatch spriteBatch,
SpriteFont spriteFont, int value,
Vector2 position, Color color)
{
Vector2 nextPosition = position;
if (value == Int32.MinValue)
{
nextPosition.X = nextPosition.X +
spriteFont.MeasureString(minValue).X;
spriteBatch.DrawString(spriteFont, minValue, position,
color);
position = nextPosition;
}
else
{
if (value < 0)
{
nextPosition.X = nextPosition.X +
spriteFont.MeasureString(“-“).X;
spriteBatch.DrawString(spriteFont, “-“, position,
color);
value = -value;
position = nextPosition;
}
int index = 0;
do
{
int modulus = value % 10;
value = value / 10;
charBuffer[index] = digits[modulus];
xposBuffer[index] = spriteFont.MeasureString
(digits[modulus]).X;
index += 1;
}
while (value > 0);
for (int i = index – 1; i >= 0; –i)
{
nextPosition.X = nextPosition.X + xposBuffer[i];
spriteBatch.DrawString(spriteFont, charBuffer[i],
position, color);
position = nextPosition;
}
}
return position;
}
}
[/code]

Taking advantage of the list for sprites

If you have a Sprites class, for example, create an object pool to reuse it rather than letting it fall out of scope and creating a new one each time one ceases to exist in the game and each time you need a new one. As an example, create a generic List<> of your Sprites class (refer http://msdn.microsoft.com/en-us/library/6sh2ey19. aspx for more information on lists). Use the List<> constructor overload that takes a default capacity and make sure to set it to a value high enough to contain all the objects of that sort and will exist at one time in your game (for example, 300). Then, use a for loop to go through and create all of the objects in the list up to the capacity. Add a public bool IsAlive { get; set; } property to your class to keep track of which ones are being used at any particular time. When you need a new one, loop through the list until you find one, where IsAlive is false. Take that one, set IsAlive to true, set the other properties (such as its position, direction, and so on.) to their appropriate values, and continue. When doing collision detection, loop through using a for or a foreach loop and process only the objects for which IsAlive is true. The same approach should be followed for updating and drawing them. Whenever one is no longer needed (for example, when it collides with something or it goes off screen), simply set its IsAlive to false and it will now be available for reuse without any memory allocation. If you want to be creative, you can expand on this further in several different ways. You could keep a count of the number of live objects, so that once you have processed that number in your update and draw methods, you can use the break keyword to get out of the loop early, rather than go all the way to the end. Alternatively, you could keep two lists: one for storing live objects and one for dead objects, and move objects between the two lists as appropriate.

Preferring struct rather than class when just an instance is needed

If you do want to create something, you can just create a new “instance” of each Update() or Draw() method. Try creating a struct instead of a class. Structures can perform most of the things that classes can (the major limitation being that they cannot inherit from another structure, a class, or anything else, but they can implement interfaces). Moreover, structures live on the stack and not on the heap, so unless you have a reference type, like a string or a class, as a field or property of the structure, you will not generate any trash using a structure. Remember, though, that an array of structures is a reference type (as are all arrays), and thus lives on the heap and counts towards the GC trigger limit whenever created.

Avoiding use of LINQ in game developing

Don’t use LINQ. It looks cool. It makes your code shorter, simpler, and perhaps even easier to read. However, LINQ queries can easily become a big source of trash. They are fine in your startup code, as you are going to generate trash there anyway, just by loading assets and preparing game resources. However, don’t use it in Update(), Draw(), or any other method that gets called during the gameplay.

Minimizing the use of ToString()

Minimize use of ToString(). At a minimum, it creates a string, which lives on the heap (refer to the Drawing integer in string without garbage section discussed earlier in this chapter). If you do need to use ToString(), try to limit how often it is called. If the string only changes every level, then generate it only once at the beginning of the level. If it only changes when a certain value changes, then generate it only when that value changes. Any limits you can set are worth it. The amount of time it takes to check a Boolean condition is so small as to be almost non-existent. You could probably fit tens and even hundreds of thousands of true/false checks for the time it takes the GC to run on a complex heap.

Windows Phone Special Effects

Using dual texture effects

Dual texture is very useful when you want to map two textures onto a model. The Windows Phone 7 XNA built-in DualTextureEffect samples the pixel color from two texture images. That is why it is called dual texture. The textures used in the effect have their own texture coordinate and can be mapped individually, tiled, rotated, and so on. The texture is mixed using the pattern:

[code]
finalTexture.color = texture1.Color * texture2.Color;
finalTexture.alpha = texture1.Alpha * texture2.Alpha;
[/code]

The color and alpha of the final texture come from a separate computation. The best practice of DualTextureEffect is to apply the lightmap on the model. In computer graphics, computing the lighting and shadows is a big performance job in real time. The lightmap texture is pre-computed and stored individually. A lightmap is a data set comprising the different surfaces of a 3D model. This will save the performance cost on lighting computation. Sometimes, you might want to use the ambient occlusion effect, which is costly. At this point, lightmap can be used as a texture, then mapped to the special model or scene for realistic effect. As the lightmap is pre-computed in 3D modeling software (you will learn how to deal with this in 3DS MAX), it is easy for you to use the most complicated lighting effects (shadows, ray-tracing, radiosity, and so on.) in Windows Phone 7. You can use the dual texture effect if you just want the game scene to have shadows and lighting. In this recipe, you will learn how to create the lightmap and apply it on your game model using the DualTextureEffect.

How to do it…

The following steps show you the process for creating the lightmap in 3DS MAX and how to use the lightmap in your Windows Phone 7 game using DualTextureEffect:

  1. Create the Sphere lightmap in 3DS MAX 2011. Open 3DS MAX 2011, in the Create panel, click the Geometry button, then create a sphere by choosing the Sphere push button, as shown in the following screenshot:
    the Geometry button
  2. Add the texture to the Material Compact Editor and apply the material to the sphere. Click the following menu items of 3DS MAX 2011: Rendering | Material Editor | Compact Material Editor. Choose the first material ball and apply the texture you want to the material ball. Here, we use the tile1.png, a checker image, which you can find in the Content directory of the example bundle file. The applied material ball looks similar to the following screenshot:
    Material Compact Editor
  3. Apply the Target Direct Light to the sphere. In the Create panel—the same panel for creating sphere—click the Lights button and choose the Target Direct option. Then drag your mouse over the sphere in the Perspective viewport and adjust the Hotspot/Beam to let the light encompass the sphere, as shown in the following screenshot:
    the Perspective viewport
  4. Render the Lightmap. When the light is set as you want, the next step is to create the lightmap. After you click the sphere that you plan to build the lightmap for, click the following menu items in 3DS MAX: Rendering | Render To Texture. In the Output panel of the pop-up window, click the Add button. Another pop-up window will show up; choose the LightingMap option, and then click Add Elements, as shown in the following screenshot:
    Rendering | Render To Texture
  5. After that, change the setting of the lightmap:
    • Change the Target Map Slot to Self-Illumination in the Output panel.
    • Change the Baked Material Settings to Output Into Source in the Baked Material panel.
    • Change the Channel to 2 in the Mapping Coordinates panel.
    • Finally, click the Render button. The generated lightmap will look similar to the following screenshot:
      the Render buttonBy default, the lightmap texture type is .tga, and the maps are placed in the images subfolder of the folder where you installed 3DS MAX. The new textures are flat. In other words, they are organized according to groups of object faces. In this example, the lightmap name is Sphere001LightingMap.tga.
  6. Open the Material Compact Editor again by clicking the menu items Rendering | Material Editor | Compact Material Editor. You will find that the first material ball has a mixed texture combined with the original texture and the lightmap. You can also see that Self-Illumination is selected and the value is Sphere001LightingMap. tga. This means the lightmap for the sphere is applied successfully.
  7. Select the sphere and export to an FBX model file named DualTextureBall.FBX, which will be used in our Windows Phone 7 game.
  8. From this step, we will render the lightmap of the sphere in our Windows Phone 7 XNA game using the new built-in effect DualTextureEffect. Now, create a Windows Phone Game project named DualTextureEffectBall in Visual Studio 2010 and change Game1.cs to DualTextureEffectBallGame.cs. Then, add the texture file tile1.png, the lightmap file Sphere001LightingMap.tga, and the model DualTextureBall.FBX to the content project.
  9. Declare the indispensable variables in the DualTextureEffectBallGame class. Add the following code to the class field:
    [code]
    // Ball Model
    Model modelBall;
    // Dual Texture Effect
    DualTextureEffect dualTextureEffect;
    // Camera
    Vector3 cameraPosition;
    Matrix view;
    Matrix projection;
    [/code]
  10. Initialize the camera. Insert the following code to the Initialize() method:
    [code]
    // Initialize the camera
    cameraPosition = new Vector3(0, 50, 200);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4,
    GraphicsDevice.Viewport.AspectRatio,
    1.0f, 1000.0f);
    [/code]
  11. Load the ball model and initialize the DualTextureEffect. Paste the following code to the LoadContent() method:
    [code]
    // Load the ball model
    modelBall = Content.Load<Model>(“DualTextureBall”);
    // Initialize the DualTextureEffect
    dualTextureEffect = new DualTextureEffect(GraphicsDevice);
    dualTextureEffect.Projection = projection;
    dualTextureEffect.View = view;
    // Set the diffuse color
    dualTextureEffect.DiffuseColor = Color.Gray.ToVector3();
    // Set the first and second texture
    dualTextureEffect.Texture =
    Content.Load<Texture2D>(“tile1”);
    dualTextureEffect.Texture2 =
    Content.Load<Texture2D>(“Sphere001LightingMap”);
    Define the DrawModel() method in the class:
    // Draw model
    private void DrawModel(Model m, Matrix world,
    DualTextureEffect effect)
    {
    foreach (ModelMesh mesh in m.Meshes)
    {
    // Iterate every part of current mesh
    foreach (ModelMeshPart meshPart in mesh.MeshParts)
    {
    // Change the original effect to the designed
    // effect
    meshPart.Effect = effect;
    // Update the world matrix
    effect.World *= world;
    }
    mesh.Draw();
    }
    }
    [/code]
  12. Draw the ball model using DualTextureEffect on the Windows Phone 7 screen. Add the following lines to the Draw() method:
    [code]
    // Rotate the ball model around axis Y.
    float timer =
    (float)gameTime.ElapsedGameTime.TotalSeconds;
    DrawModel(modelBall, Matrix.CreateRotationY(timer),
    dualTextureEffect);
    [/code]
  13. Build and run the example. It should run as shown in the following screenshot:
    DualTextureEffect
  14. If you comment the following line in LoadContent() to disable the lightmap texture, you will find the difference when lightmap is on or off:
    [code]
    dualTextureEffect.Texture2 =
    Content.Load<Texture2D>(“Sphere001LightingMap”);
    [/code]
  15. Run the application without lightmap. The model will be in pure black as shown in the following screenshot:
    dual texture effects

How it works…

Steps 1–6 are to create the sphere and its lightmap in 3DS MAX 2011.

In step 8, the modelBall is responsible for loading and holding the ball model. The dualTextureEffect is the object of XNA 4.0 built-in effect DualTextureEffect for rendering the ball model with its original texture and the lightmap. The following three variables cameraPosition, view, and projection represent the camera.

In step 10, the first line is to load the ball model. The rest of the lines initialize the DualTextureEffect. Notice, we use the tile1.png for the first and original texture, and the Sphere001LightingMap.tga for the lightmap as the second texture.

In step 11, the DrawModel() method is different from the definition. Here, we need to replace the original effect of each mesh with the DualTextureEffect. When we iterate the mesh parts of every mesh of the current model, we assign the effect to the meshPart.Effect for applying the DualTextureEffect to the mesh part.

Using environment map effects

In computer games, environment mapping is an efficient image-based lighting technique for aligning the reflective surface with the distant environment surrounding the rendered object. In Need for Speed, produced by Electronic Arts, if you open the special visual effect option while playing the game, you will find the car body reflects the scene around it, which may be trees, clouds, mountains, or buildings. They are amazing and attractive. This is environment mapping, it makes games more realistic. The methods for storing the surrounding environment include sphere mapping and cube mapping, pyramid mapping, and the octahedron mapping. In XNA 4.0, the framework uses cube mapping, in which the environment is projected onto the six faces of a cube and stored as six square textures unfolded into six square regions of a single texture. In this recipe, you will learn how to make a cubemap using the DirectX texture tool, and apply the cube map on a model using EnvironmentMappingEffect.

Getting ready

Cubemap is used in real-time engines to fake refractions. It’s way faster than ray-tracing because they are only textures mapped as a cube. So that’s six images (one for each face of the cube).

For creating the cube map for the environment map effect, you should use the DirectX Texture Tool in the DirectX SDK Utilities folder. The latest version of Microsoft DirectX SDK can be downloaded from the URL http://www.microsoft.com/downloads/en/ details.aspx?FamilyID=3021d52b-514e-41d3-ad02-438a3ba730ba.

How to do it…

The following steps lead you to create an application using the Environment Mapping effect:

  1. From this step, we will create the cube map in DirectX Texture Tool. Run this application and create a new Cube Map. Click the following menu items: File | New Texture. A window will pop-up; in this window, choose the Cubemap Texture for Texture Type; change the dimension to 512 * 512 in the Dimensions panel; set the Surface/Volume Format to Four CC 4-bit: DXT1. The final settings should look similar to the following screenshot:
    Cubemap Texture
  2. Set the texture of every face of the cube. Choose a face for setting the texture by clicking the following menu items: View | Cube Map Face | Positive X, as shown in the following screenshot:
    Cube Map Face | Positive X
  3. Then, apply the image for the Positive X face by clicking: File | Open Onto This Cubemap Face, as shown in the following screenshot:
    Open Onto This Cubemap Face
  4. When you click the item, a pop-up dialog will ask you to choose a proper image for this face. In this example, the Positive X face will look similar to the following screenshot:
    Positive X face will look similar
  5. It is similar for the other five faces, Negative X, Positive Y, Negative Y, Positive Z, and Negative Z. When all of the cube faces are appropriately set, we save cubemap as SkyCubeMap.dds. The cube map will look similar to the following figure:
    Negative X, Positive Y, Negative Y, Positive Z, and Negative Z
  6. From this step, we will start to render the ball model using the XNA 4.0 built-in effect called EnvironmentMapEffect. Create a Windows Phone Game project named EnvironmentMapEffectBall in Visual Studio 2010 and change Game1.cs to EnvironmentMapEffectBallGame.cs. Then, add the ball model file ball.FBX, ball texture file silver.jpg, and the generated cube map from DirectX Texture Tool SkyCubemap.dds to the content project.
  7. Declare the necessary variables of the EnvironmentMapEffectBallGame class. Add the following lines to the class:
    [code]
    // Ball model
    Model modelBall;
    // Environment Map Effect
    EnvironmentMapEffect environmentEffect;
    // Cube map texture
    TextureCube textureCube;
    // Ball texture
    Texture2D texture;
    // Camera
    Vector3 cameraPosition;
    Matrix view;
    Matrix projection;
    [/code]
  8. Initialize the camera. Insert the following lines to the Initialize() method:
    [code]
    // Initialize the camera
    cameraPosition = new Vector3(2, 3, 32);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4,
    GraphicsDevice.Viewport.AspectRatio,
    1.0f, 100.0f);
    [/code]
  9. Load the ball model, ball texture, and the sky cube map. Then initialize the environment map effect and set its properties. Paste the following code in the LoadContent() method:
    [code]
    // Load the ball model
    modelBall = Content.Load<Model>(“ball”);
    // Load the sky cube map
    textureCube = Content.Load<TextureCube>(“SkyCubeMap”);
    // Load the ball texture
    texture = Content.Load<Texture2D>(“Silver”);
    // Initialize the EnvironmentMapEffect
    environmentEffect = new EnvironmentMapEffect(GraphicsDevice);
    environmentEffect.Projection = projection;
    environmentEffect.View = view;
    // Set the initial texture
    environmentEffect.Texture = texture;
    // Set the environment map
    environmentEffect.EnvironmentMap = textureCube;
    environmentEffect.EnableDefaultLighting();
    // Set the environment effect factors
    environmentEffect.EnvironmentMapAmount = 1.0f;
    environmentEffect.FresnelFactor = 1.0f;
    environmentEffect.EnvironmentMapSpecular = Vector3.Zero;
    [/code]
  10. Define the DrawModel() of the class:
    [code]
    // Draw Model
    private void DrawModel(Model m, Matrix world,
    EnvironmentMapEffect environmentMapEffect)
    {
    foreach (ModelMesh mesh in m.Meshes)
    {
    foreach (ModelMeshPart meshPart in mesh.MeshParts)
    {
    meshPart.Effect = environmentMapEffect;
    environmentMapEffect.World = world;
    }
    mesh.Draw();
    }
    }
    [/code]
  11. Draw and rotate the ball with EnvironmentMapEffect on the Windows Phone 7 screen. Insert the following code to the Draw() method:
    [code]
    // Draw and rotate the ball model float time = (float)gameTime.TotalGameTime.TotalSeconds; DrawModel(modelBall, Matrix.CreateRotationY(time * 0.3f) * Matrix.CreateRotationX(time), environmentEffect);
    [/code]
  12. Build and run the application. It should run similar to the following screenshot:
    environment map effects

How it works…

Steps 1 and 2 use the DirectX Texture Tool to generate a sky cube map for the XNA 4.0 built-in effect EnvironmentMapEffect.

In step 4, the modelBall loads the ball model, environmentEffect will be used to render the ball model in EnvironmentMapEffect, and textureCube is a cube map texture. The EnvironmentMapEffect will receive the texture as an EnvironmentMap property; texture represents the ball texture; the last three variables cameraPosition, view, and projection are responsible for initializing and controlling the camera.

In step 6, the first three lines are used to load the required contents including the ball model, texture, and the sky cube map. Then, we instantiate the object of EnvironmentMapEffect and set its properties. environmentEffect.Projection and environmentEffect. View are for the camera; environmentEffect.Texture is for mapping ball texture onto the ball model; environmentEffect.EnvironmentMap is the environment map from which the ball model will get the reflected color and mix it with its original texture.

The EnvironmentMapAmount is a float that describes how much of the environment map could show up, which also means how much of the cube map texture will blend over the texture on the model. The values range from 0 to 1 and the default value is 1.

The FresnelFactor makes the environment map visible independent of the viewing angle. Use a higher value to make the environment map visible around the edges; use a lower value to make the environment map visible everywhere. Fresnel lighting only affects the environment map color (RGB values); alpha is not affected. The value ranges from 0.0 to 1.0. 0.0 is used to disable the Fresnel Lighting. 1.0 is the default value.

The EnvironmentMapSpecular implements cheap specular lighting, by encoding one or more specular highlight patterns into the environment map alpha channel, then setting the EnvironmentMapSpecular to the desired specular light color.

In step 7, we replace the default effect of every mesh part of the model meshes with the EnvironmentMapEffect, and draw the mesh with replaced effect.

Rendering different parts of a character into textures using RenderTarget2D

Sometimes, you want to see a special part of a model or an image, and you also want to see the original view of them at the same time. This is where, the render target will help you. From the definition of render target in DirectX, a render target is a buffer where the video card draws pixels for a scene that is being rendered by an effect class. In Windows Phone 7, the independent video card is not supported. The device has an embedded processing unit for graphic rendering. The major application of render target in Windows Phone 7 is to render the viewing scene, which is in 2D or 3D, into 2D texture. You can manipulate the texture for special effects such as transition, partly showing, or something similar. In this recipe, you will discover how to render different parts of a model into texture and then draw them on the Windows Phone 7 screen.

Getting ready

Render target, by default, is called the back buffer. This is the part of the video memory that contains the next frame to be drawn. You can create other render targets with the RenderTarget2D class, reserving new regions of video memory for drawing. Most games render a lot of content to other render targets besides the back buffer (offscreen), then assemble the different graphical elements in stages, combining them to create the final product in the back buffer.

A render target has a width and height. The width and height of the back buffer are the final resolution of your game. An offscreen render target does not need to have the same width and height as the back buffer. Small parts of the final image can be rendered in small render targets, and copied to another render target later. To use a render target, create a RenderTarget2D object with the width, height, and other options you prefer. Then, call GraphicsDevice.SetRenderTarget to make your render target the current render target. From this point on, any Draw calls you make will draw into your render target because the RenderTarget2D is the subclass of Texture2D. When you are finished with the render target, call GraphicsDevice.SetRenderTarget to a new render target (or null for the back buffer).

How to do it…

In the following steps, you will learn how to use RenderTarget2D to render different parts of a designated model into textures and present them on the Windows Phone 7 screen:

  1. Create a Windows Phone Game project named RenderTargetCharacter in Visual Studio 2010 and change Game1.cs to RenderTargetCharacterGame.cs. Then, add the character model file character.FBX and the character texture file Blaze. tga to the content project.
  2. Declare the required variables in the RenderTargetCharacterGame class field. Add the following lines of code to the class field:
    [code]
    // Character model
    Model modelCharacter;
    // Character model world position
    Matrix worldCharacter = Matrix.Identity;
    // Camera
    Vector3 cameraPosition;
    Vector3 cameraTarget;
    Matrix view;
    Matrix projection;
    // RenderTarget2D objects for rendering the head, left //fist,
    and right foot of character
    RenderTarget2D renderTarget2DHead;
    RenderTarget2D renderTarget2DLeftFist;
    RenderTarget2D renderTarget2DRightFoot;
    [/code]
  3. Initialize the camera and render targets. Insert the following code to the Initialize() method:
    [code]
    // Initialize the camera
    cameraPosition = new Vector3(0, 40, 350);
    cameraTarget = new Vector3(0, 0, 1000);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4,
    GraphicsDevice.Viewport.AspectRatio,
    0.1f, 1000.0f);
    // Initialize the RenderTarget2D objects with different sizes
    renderTarget2DHead = new RenderTarget2D(GraphicsDevice,
    196, 118, false, SurfaceFormat.Color,
    DepthFormat.Depth24, 0,
    RenderTargetUsage.DiscardContents);
    renderTarget2DLeftFist = new RenderTarget2D(GraphicsDevice,
    100, 60, false, SurfaceFormat.Color,
    DepthFormat.Depth24,
    0, RenderTargetUsage.DiscardContents);
    renderTarget2DRightFoot = new
    RenderTarget2D(GraphicsDevice, 100, 60, false,
    SurfaceFormat.Color, DepthFormat.Depth24, 0,
    RenderTargetUsage.DiscardContents);
    [/code]
  4. Load the character model and insert the following line of code to the LoadContent() method:
    [code]
    modelCharacter = Content.Load<Model>(“Character”);
    [/code]
  5. Define the DrawModel() method:
    [code]
    // Draw the model on screen
    public void DrawModel(Model model, Matrix world, Matrix view,
    Matrix projection)
    {
    Matrix[] transforms = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(transforms);
    foreach (ModelMesh mesh in model.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.EnableDefaultLighting();
    effect.DiffuseColor = Color.White.ToVector3();
    effect.World =
    transforms[mesh.ParentBone.Index] * world;
    effect.View = view;
    effect.Projection = projection;
    }
    mesh.Draw();
    }
    }
    [/code]
  6. Get the rendertargets of the right foot, left fist, and head of the character. Then draw the rendertarget textures onto the Windows Phone 7 screen. Insert the following code to the Draw() method:
    [code]
    // Get the rendertarget of character head
    GraphicsDevice.SetRenderTarget(renderTarget2DHead);
    GraphicsDevice.Clear(Color.Blue);
    cameraPosition = new Vector3(0, 110, 60);
    cameraTarget = new Vector3(0, 110, -1000);
    view = Matrix.CreateLookAt(cameraPosition, cameraTarget,
    Vector3.Up);
    DrawModel(modelCharacter, worldCharacter, view,
    projection);
    GraphicsDevice.SetRenderTarget(null);
    // Get the rendertarget of character left fist
    GraphicsDevice.SetRenderTarget(renderTarget2DLeftFist);
    GraphicsDevice.Clear(Color.Blue);
    cameraPosition = new Vector3(-35, -5, 40);
    cameraTarget = new Vector3(0, 5, -1000);
    view = Matrix.CreateLookAt(cameraPosition, cameraTarget,
    Vector3.Up);
    DrawModel(modelCharacter, worldCharacter, view,
    projection);
    GraphicsDevice.SetRenderTarget(null);
    // Get the rendertarget of character right foot
    GraphicsDevice.SetRenderTarget(renderTarget2DRightFoot);
    GraphicsDevice.Clear(Color.Blue);
    cameraPosition = new Vector3(20, -120, 40);
    cameraTarget = new Vector3(0, -120, -1000);
    view = Matrix.CreateLookAt(cameraPosition, cameraTarget,
    Vector3.Up);
    DrawModel(modelCharacter, worldCharacter, view,
    projection);
    GraphicsDevice.SetRenderTarget(null);
    // Draw the character model
    cameraPosition = new Vector3(0, 40, 350);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    GraphicsDevice.Clear(Color.CornflowerBlue);
    DrawModel(modelCharacter, worldCharacter, view,
    projection);
    // Draw the generated rendertargets of different parts of
    // character model in 2D
    spriteBatch.Begin();
    spriteBatch.Draw(renderTarget2DHead, new Vector2(500, 0),
    Color.White);
    spriteBatch.Draw(renderTarget2DLeftFist, new Vector2(200,
    220),
    Color.White);
    spriteBatch.Draw(renderTarget2DRightFoot, new Vector2(500,
    400),
    Color.White);
    spriteBatch.End();
    [/code]
  7. Build and run the application. The application will run as shown in the following screenshot:
    RenderTarget2D

How it works…

In step 2, the modelCharacter loads the character 3D model and the worldCharacter represents the world transformation matrix of the character. The following four variables cameraPosition, cameraTarget, view, and projection are used to initialize the camera. Here, the cameraTarget will have the same Y value as the cameraPosition and large enough Z value, which is far away behind the center, because we want the camera’s look-at direction to be parallel to the XZ plane. The last three RenderTarget2D objects, renderTarget2DHead, renderTarget2DLeftFist, and renderTarget2DRightFoot, are responsible for rendering the different parts of the character from 3D real-time view to 2D texture.

In step 3, we initialize the camera and the three render targets. The initialization code for the camera is nothing new. The RenderTarget2D has three overloaded constructers, and the most complex one is the third. If you understand the third, the other two are easy. This constructor looks similar to the following code:

[code]
public RenderTarget2D (
GraphicsDevice graphicsDevice,
int width,
int height,
bool mipMap,
SurfaceFormat preferredFormat,
DepthFormat preferredDepthFormat,
int preferredMultiSampleCount,
RenderTargetUsage usage
)
[/code]

Let’s have a look at what all these parameters stand for:

  • graphicsDevice: This is the graphic device associated with the render target resource.
  • width: This is an integer, in pixels, of the render target. You can use graphicsDevice.PresentationParameters.BackBufferWidth to get the current screen width. Because the RenderTarget2D is a subclass of Texture2D, the value for width and height of RenderTarget2D objects are used to define the size of the final RenderTarget2D texture. Notice, the maximum size for Texture2D in Windows Phone 7 is less than 2048, so the width value of RenderTarget2D cannot be beyond this limitation.
  • height: This is an integer, in pixels, of the render target. You can use graphicsDevice.PresentationParameters.BackBufferHeight to get the current screen height. The additional information is similar to the width parameter.
  • mipMap: This is true to enable a full mipMap chain to be generated, otherwise false.
  • preferredFormat: This is the preferred format for the surface data. This is the format preferred by the application, which may or may not be available from the hardware. In the XNA Framework, all two-dimensional (2D) images are represented by a range of memory called a surface. Within a surface, each element holds a color value representing a small section of the image, called a pixel. An image’s detail level is defined by the number of pixels needed to represent the image and the number of bits needed for the image’s color spectrum. For example, an image that is 800 pixels wide and 600 pixels high with 32 bits of color for each pixel (written as 800 x 600 x 32) is more detailed than an image that is 640 pixels wide and 480 pixels tall with 16 bits of color for each pixel (written as 640 x 480 x 16). Likewise, the more detailed image requires a larger surface to store the data. For an 800 x 600 x 32 image, the surface’s array dimensions are 800 x 600, and each element holds a 32-bit value to represent its color.

    All formats are listed from left to right, most-significant bit to least-significant bit. For example, ARGB formats are ordered from the most-significant bit channel A (alpha), to the least-significant bit channel B (blue). When traversing surface data, the data is stored in memory from least-significant bit to most-significant bit, which means that the channel order in memory is from least-significant bit (blue) to most-significant bit (alpha).

    The default value for formats that contain undefined channels (Rg32, Alpha8, and so on) is 1. The only exception is the Alpha8 format, which is initialized to 000 for the three color channels. Here, we use the SurfaceFormat.Color option. The SurfaceFormat.Color is an unsigned format, 32-bit ARGB pixel format with alpha, using 8 bits per channel.

  • preferredDepthFormat: This is a depth buffer containing depth data and possibly stencil data. You can control a depth buffer using a state object. The depth format includes Depth16, Depth24, and Depth24 Stencil.
  • usage: This is the object of RenderTargetUsage. It determines how render target data is used once a new target is set. This enumeration has three values: PreserveContents, PlatformContents, and DiscardContents. The default value DiscardContents means whenever a rendertarget is set onto the device, the previous one will be destroyed first. On the other hand, when you choose the PreserveContents option, the data associated with the render target will be maintained if a new rendertarget is set. This method will impact the performance greatly because it stores data and copies it all back to rendertarget when you use it again. The PlatformContents will either clear or keep the data, depending on the current platform. On Xbox 360 and Windows Phone 7, the render target will discard contents. On PC, the render target will discard the contents if multi-sampling is enabled, and preserve the contents if not.

In step 6, the first part of the Draw() method gets the render target texture for the head of the character, the GraphicDevice.SetRenderTarget() sets a new render target for this device. As the application runs on Windows Phone 7 and the RenderTargetUsage is set to DiscardContents, every time a new render target is assigned onto the device, the previous one will be destroyed. From XNA 4.0 SDK, the method has some restrictions while calling. They are as follows:

  • The multi-sample type must be the same for the render target and the depth stencil surface
  • The formats must be compatible for the render target and the depth stencil surface
  • The size of the depth stencil surface must be greater than, or equal to, the size of the render target

These restrictions are validated only while using the debug runtime when any of the GraphicsDevice drawing methods are called. Then, the following lines until the GraphicsDevice.SetRenderTarget(null) are used to adjust the camera position and the look-at target for rendering the head of the character. The block of code points out the view for transforming and rendering the model from 3D to 2D texture as render target, which will be displayed at the designated place on the Windows Phone screen. The method calling of GraphicsDevice.SetRenderTarget(null) will reset the render target currently on the graphics device for the next render target using it. It is similar to renderTarget2DRightFoot and renderTarget2DLeftFist in the second and third part of the Draw() method. The fourth part is to draw the actual character 3D model. After that, we will present all of the generated render targets on the Windows Phone 7 screen using the 2D drawing methods.

Creating a screen transition effect using RenderTarget2D

Do you remember the scene transition in Star Wars? The scene transition is a very common method for smoothly changing the movie scene from current to next. The frequent transition patterns are Swiping, Rotating, Fading, Checkerboard Scattering, and so on. With the proper transition effects, the audience will know that the plots go well when the stage changes. Besides movies, the transition effects also have a relevant application in video games, especially in 2D games. Every game state change will trigger a transition effect. In this recipe, you will learn how to create a typical transition effect using RenderTarget2D for your Windows Phone 7 game.

How to do it…

The following steps will draw a spinning squares transition effect using the RenderTarget2D technique:

  1. Create a Windows Phone Game named RenderTargetTransitionEffect and change Game1.cs to RenderTargetTransitionEffectGame.cs. Then, add Image1.png and Image2.png to the content project.
  2. Declare the indispensable variables. Insert the following code to the RenderTargetTransitionEffectGame code field:
    [code]
    // The first forefront and background images
    Texture2D textureForeFront;
    Texture2D textureBackground;
    // the width of each divided image
    int xfactor = 800 / 8;
    // the height of each divided image
    int yfactor = 480 / 8;
    // The render target for the transition effect
    RenderTarget2D transitionRenderTarget;
    float alpha = 1;
    // the time counter
    float timer = 0;
    const float TransitionSpeed = 1.5f;
    [/code]
  3. Load the forefront and background images, and initialize the render target for the jumping sprites transition effect. Add the following code to the LoadContent() method:
    [code]
    // Load the forefront and the background image
    textureForeFront = Content.Load<Texture2D>(“Image1”);
    textureBackground = Content.Load<Texture2D>(“Image2”);
    // Initialize the render target
    transitionRenderTarget = new RenderTarget2D(GraphicsDevice,
    800, 480, false, SurfaceFormat.Color,
    DepthFormat.Depth24, 0,
    RenderTargetUsage.DiscardContents);
    [/code]
  4. Define the core method DrawJumpingSpritesTransition() for the jumping sprites transition effect. Paste the following lines into the RenderTargetTransitionEffectGame class:
    [code]
    void DrawJumpingSpritesTransition(float delta, float alpha,
    RenderTarget2D renderTarget)
    {
    // Instance a new random object for generating random
    //values to change the rotation, scale and position
    //values of each sub divided images
    Random random = new Random();
    // Divide the image into designated pieces,
    //here 8 * 8 = 64
    // ones.
    for (int x = 0; x < 8; x++)
    {
    for (int y = 0; y < 8; y++)
    {
    // Define the size of each piece
    Rectangle rect = new Rectangle(xfactor * x,
    yfactor * y, xfactor, yfactor);
    // Define the origin center for rotation and
    //scale of the current subimage
    Vector2 origin =
    new Vector2(rect.Width, rect.Height) / 2;
    float rotation =
    (float)(random.NextDouble() – 0.5f) *
    delta * 20;
    float scale = 1 +
    (float)(random.NextDouble() – 0.5f) *
    delta * 20;
    // Randomly change the position of current
    //divided subimage
    Vector2 pos =
    new Vector2(rect.Center.X, rect.Center.Y);
    pos.X += (float)(random.NextDouble()) ;
    pos.Y += (float)(random.NextDouble()) ;
    // Draw the current sub image
    spriteBatch.Draw(renderTarget, pos, rect,
    Color.White * alpha, rotation, origin,
    scale, 0, 0);
    }
    }
    }
    [/code]
  5. Get the render target of the forefront image and draw the jumping sprites transition effect by calling the DrawJumpingSpritesTransition() method. Insert the following code to the Draw() method:
    [code]
    // Render the forefront image to render target texture
    GraphicsDevice.SetRenderTarget(transitionRenderTarget);
    spriteBatch.Begin();
    spriteBatch.Draw(textureForeFront, new Vector2(0, 0),
    Color.White);
    spriteBatch.End();
    GraphicsDevice.SetRenderTarget(null);
    // Get the total elapsed game time
    timer += (float)(gameTime.ElapsedGameTime.TotalSeconds);
    // Compute the delta value in every frame
    float delta = timer / TransitionSpeed * 0.01f;
    // Minus the alpha to change the image from opaque to
    //transparent using the delta value
    alpha -= delta;
    // Draw the jumping sprites transition effect
    spriteBatch.Begin();
    spriteBatch.Draw(textureBackground, Vector2.Zero,
    Color.White);
    DrawJumpingSpritesTransition(delta, alpha,
    transitionRenderTarget);
    spriteBatch.End();
    [/code]
  6. Build and run the application. It should run similar to the following screenshots:
    transition effect using RenderTarget2D

How it works…

In step 2, the textureForeFront and textureBackground will load the forefront and background images prepared for the jumping sprites transition effect. The xfactor and yfactor define the size of each subdivided image used in the transition effect. transitionRenderTarget is the RenderTarget2D object that will render the foreground image into render target texture for the jumping sprites transition effect. The alpha variable will control the transparency of each subimage and timer will accumulate the total elapsed game time. The TransitionSpeed is a constant value that defines the transition speed.

In step 4, we define the core method DrawJumpingSpritesTransition() for drawing the jumping sprites effect. First of all, we instantiate a Random object, and the random value generated from the object will be used to randomly change the rotation, scale, and position values of the divided subimages in the transition effect. In the following loop, we iterate every subimage row by row and column by column. When it is located at one of the subimages, we create a Rectangle object with the pre-defined size. Then, we change the origin point to the image center; this will make the image rotate and scale in place. After that, we randomly change the rotation, scale, and the position values. Finally, we draw the current subimage on the Windows Phone 7 screen.

In step 5, we draw the forefront image first, because we want the transition effect on the forefront image. Then using the render target, transform the current view to the render target texture by putting the drawing code between the GraphicsDevice.SetRenderTarget(tr ansitionRenderTarget) and GraphicsDevice.SetRenderTarget(null) methods. Next, we use the accumulated elapsed game time to compute the delta value to minus the alpha value. The alpha will be used in the SpriteBatch.Draw() method to make the subimages of the jumping sprites change from opaque to transparent. The last part in the Draw() method is to draw the background image first, then draw the transition effect. This drawing order is important. The texture that has the transition effect must be drawn after the images without the transition effect. Otherwise, you will not see the effect you want.

Windows Phone Embedding Audio in your Game

Controlling an audio file

Music has the ability to impact the emotions of human beings. Different styles of music produce different feelings. Fast tempo music makes people feel nervous or excited; when the tempo becomes slow, people feel relaxed and safe. In modern video games, music often plays an important role in creating the atmosphere. Game designers and composers work together to tailor the music to the plot. When a player goes into a beautiful scene, a euphonious and harmonious song will accompany it; when immersed in a dangerous situation, the music will sound oppressive. In this recipe, you will learn how to use the media technology to control music in your Windows Phone 7 game.

Getting ready

In Windows Phone 7 XNA, a song or music is encapsulated as a Song class. This class provides the metadata of a song and includes the song’s name, artist, album, and duration. The Name and Duration are the most direct properties for your song. We will use them in our example. As a class design consideration, the Song class does not have a Play() method to play a song. You should use the MediaPlayer class, which provides methods and properties for playing songs. To control song playback, we can use the following methods:

  • Play(): The Play() method kicks off the song.
  • Stop(): The Stop() method stops the song playing and sets the playing position to the song’s beginning.
  • Pause(): The Pause() method also stops the song playing, the difference between the Pause() and the Stop() method is that the Pause() method will not reset the playing position to the start. Instead, it keeps the playing position at the place where the song is paused.
  • Resume(): The Resume() method replays the song from the paused position.

Besides these essential methods, if you have more than one song in your playing queue, the MoveNext() and MovePrevious() methods will help you to do circular playing. The two methods move to the next or previous song in the queue. They operate as if playing the queue was circular. That is, when the last song is playing the MoveNext() method moves to the first song and when the first song is playing the MovePrevious() method moves to the last song. If the IsShuffled property is set, the MoveNext() and MovePrevious() methods will randomly choose a song in the playing queue to play. To use these methods, there is no need to instantiate the MediaPlayer class, which is actually a static class. You can directly call the method using the following pattern:

[code]
MediaPlayer.MethodName()
[/code]

In this example, we will play, pause, resume, and stop a song using the MediaPlayer and Song classes. Besides this, the song’s name, playing state, and position will be displayed on the Windows Phone 7 screen.

How to do it…

The following steps show you how to load, play, pause, and resume a song in the Windows Phone7 XNA application:

  1. Create a Windows Phone Game named PlayMusic, and change Game1.cs to PlayMusicGame.cs. Add the audio file music.wma and the sprite font file gameFont.spritefont to the content project.
  2. Declare the indispensable variable. Add the following lines to the field of the PlayMusicGame class:
    [code]
    // SpriteFont object for showing song information
    SpriteFont font;
    // Text presents the song playing position
    string textPlayingPosition = “”;
    // Song’s name
    string textSongName;
    // Playing state
    MediaState PlayingState;
    // Song object stores a song
    Song song;
    [/code]
  3. Load the game font and the audio file. Then get the song’s name and play it. Add the following code to the LoadContent() method:
    [code]
    // Load the game font
    font = Content.Load<SpriteFont>(“gameFont”);
    // Load the song
    song = Content.Load<Song>(“music”);
    // Get the song’s name
    textSongName = song.Name;
    // Play the song
    MediaPlayer.Play(song);
    [/code]
  4. Use the MediaPlayer class to play, pause, resume, and stop the song. Meanwhile, update the playing state and position. Insert the following code to the Update() method:
    [code]
    // Get the tapped position
    TouchCollection touches = TouchPanel.GetState();
    if (touches.Count > 0 && touches[0].State ==
    TouchLocationState.Pressed)
    {
    Point point = new Point((int)touches[0].Position.X,
    (int)touches[0].Position.Y);
    // If the tap gesture is valid
    if (GraphicsDevice.Viewport.Bounds.Contains(point))
    {
    // If the the media player is playing, pause the
    // playing song
    if (MediaPlayer.State == MediaState.Playing)
    {
    MediaPlayer.Pause();
    PlayingState = MediaState.Paused;
    }
    else if (MediaPlayer.State == MediaState.Paused)
    {
    // If the song is paused and not stopped, resume
    //it
    MediaPlayer.Resume();
    PlayingState = MediaState.Playing;
    }
    else if (MediaPlayer.State == MediaState.Stopped)
    {
    // If the song is stopped, replay it
    MediaPlayer.Play(song);
    PlayingState = MediaState.Playing;
    }
    }
    }
    if (MediaPlayer.State == MediaState.Playing)
    {
    // If the song’s playing position meets the end, stop
    // playing
    if (MediaPlayer.PlayPosition == song.Duration)
    {
    MediaPlayer.Stop();
    PlayingState = MediaState.Stopped;
    }
    // Show the song’s playing position and the total duration
    textPlayingPosition = MediaPlayer.PlayPosition.ToString()
    + ” / ” + song.Duration.ToString();
    }
    [/code]
  5. Draw the song’s name, playing state, and playing position on the Windows Phone 7 screen. Add the following code to the Draw() method:
    [code]
    spriteBatch.Begin();
    // Draw the instruction text
    spriteBatch.DrawString(font, “Tap Screen to Play, Pause and ”
    +”Resume the Song”, new Vector2(0, 0), Color.White);
    // Draw the song’s name
    spriteBatch.DrawString(font, “Song’s Name: ” + textSongName,
    new Vector2(0,200 ), Color.White);
    // Draw the song’s playing state
    spriteBatch.DrawString(font, “State: ” +
    PlayingState.ToString(),
    new Vector2(0, 240), Color.White);
    spriteBatch.DrawString(font, textPlayingPosition,
    new Vector2(0, 280), Color.White);
    spriteBatch.End();
    [/code]
  6. Now, build and run the application; it should run as shown in the following screenshot:

Controlling an audio file

How it works…

In step 2, font will be used to show the instructions, song’s name, playing state, and position; the texPlayingPosition stores the song’s current playing position; textSongName saves the song’s name; PlayingState shows the song’s playing state: Playing, Paused, or Stopped; the song is the object of the Song class and will be used to process and load an audio file.

In step 4, the first part of the Update() method is to check whether the player taps on the Windows Phone 7 screen; if he/she does, it has three MediaState options for controlling the song. When the song is Playing, the tap gesture will pause it; if the song is Paused, the gesture will replay it from the paused position using the MediaPlayer.Resume() method; once the song’s current MediaState is Stopped, we will replay the song from the beginning when a valid tap gesture takes place. The second part is about updating the song’s current playing position with its total duration using the two properties of the Song class: PlayPosition and Duration. Besides these, when the current playing position equals the song’s duration, it means the song has ended. In this example, we will replay the song once. You can change it in another way by moving to the next song.

Adding sound effects to your game

“The sound effects are artificially created or enhanced sounds or sound processes used to emphasize artistic or other content of films, television shows, live performance, animation, video game, music, or other media.” – Wiki.

When you are playing games such as Counter Strike or Quake, the sound you hear while firing is the sound effect. Every weapon has its corresponding sound effect. In the early times, the sound effect came from the sound synthesis, a kind of midi rhythm. Today, the game studio can sample the sound from real instances. In making a racing game, the engine sound of every car is different. The game studio can record the sound from a real car, maybe a Lamborghini or a Panamera Turbo, to make the game more realistic. The Windows Phone 7 XNA framework simplifies the work needed to control sound effects. It is up to you to use the sound effects in your game. In this recipe, you will learn how to make your game more interesting by applying sound effects.

Getting ready

In XNA, a SoundEffect contains the audio data and metadata (such as wave data and loop information) loaded from a sound file. You can create multiple SoundEffectInstance objects, and play them from a single SoundEffect. These objects share the resources of that SoundEffect. The only limit to the number of loaded SoundEffect instances is memory. A loaded SoundEffect will continue to hold its memory resources throughout its lifetime. When a SoundEffect instance is destroyed, all SoundEffectInstance objects previously created by that SoundEffect will stop playing and become invalid. Unlike the Song class, SoundEffect has a Play() method; usually, the sound effect is fast and short, plays once and then stops. If you do not want to loop a sound, the Play() method is enough. Otherwise, you should create an instance of the sound effect using the SoundEffect. CreateInstance() method. As the basic metadata, the SoundEffect class also has Name and Duration properties, and it is easy to get the name of any sound effect and its duration. The DistanceScale and DopplerScale properties will help you to simulate a realistic 3D sound effect, especially when you use the SoundEffectInstance.Apply3D() method.

For DistanceScale, if sounds are attenuating too fast, which means that the sounds get quiet too quickly as they move away from the listener, you need to increase the DistanceScale. If sounds are not attenuating fast enough, decrease the DistanceScale. This property will also affect Doppler sound.

The DopplerScale changes the relative velocities of emitters and listeners. If sounds are shifting (pitch) too much for the given relative velocity of the emitter and listener, decrease the DopplerScale. If sounds are not shifting enough for the given relative velocity of the emitter and listener, increase the DopplerScale.

In this example, we will use the SoundEffect class to play two different weapons’ sounds.

How to do it…

The following steps present a complete guide for controlling a sound effect in a Windows Phone 7 XNA game using a .wav file:

  1. Create a Windows Phone Game named PlaySoundEffect, and change the Game1. cs to PlaySoundEffectGame.cs. Add the audio file Laser.wav, MachineGun. wav and the sprite font file gameFont.spritefont to the project content.
  2. Add the following code as the required variables to the field of PlaySoundEffectGame class:
    [code]
    // Sprite font for showing the name of current sound effect
    SpriteFont font;
    // Current weapon’s name
    string CurrentWeapon;
    // Sound effect variables
    SoundEffect SoundEffectLaser;
    SoundEffect soundEffectMachineGun;
    // Current Sound effect
    SoundEffect soundEffectPlaying;
    [/code]
  3. Enable the Hold gesture for Windows Phone 7 TouchPanel. Add the following line to the Initialize() method:
    [code]
    // Enable the hold gesture
    TouchPanel.EnabledGestures = GestureType.Hold;
    [/code]
  4. Load the game font, sound effects of weapons, and set the current sound effect of a weapon for playing. Paste the following code into the LoadContent() method:
    [code]
    // Load the font
    font = Content.Load<SpriteFont>(“gameFont”);
    // Load the sound effect of laser gun
    SoundEffectLaser = Content.Load<SoundEffect>(“Laser”);
    // Load the sound effect of machine gun
    soundEffectMachineGun = Content.Load<SoundEffect>(“MachineG
    un”);
    // Set the sound effect of laser to the current sound effect
    // for playing
    soundEffectPlaying = SoundEffectLaser;
    // Set the name of current sound effect
    CurrentWeapon = “Laser”;
    [/code]
  5. Play the sound effect and use the Hold gesture to switch the sound effects between different weapons. Add the following code to the Update() method:
    [code]
    // Play the current sound effect when tap on the screen
    TouchCollection touches = TouchPanel.GetState();
    if (touches.Count > 0 && touches[0].State ==
    TouchLocationState.Pressed)
    {
    Point point = new Point((int)touches[0].Position.X,
    (int)touches[0].Position.Y);
    if (GraphicsDevice.Viewport.Bounds.Contains(point))
    {
    if (soundEffectPlaying != null)
    {
    soundEffectPlaying.Play();
    }
    }
    }
    // Using Hold gesture to change the sound effect of weapons
    while(TouchPanel.IsGestureAvailable)
    {
    // Read the gesture
    GestureSample gestures = TouchPanel.ReadGesture();
    if (gestures.GestureType == GestureType.Hold)
    {
    // If the Hold gesture is taking place, change the
    // sound effect.
    if (soundEffectPlaying.Equals(soundEffectLaser))
    {
    soundEffectPlaying = soundEffectMachineGun;
    CurrentWeapon = “Machine Gun”;
    }
    else if (soundEffectPlaying.Equals
    (soundEffectMachineGun))
    {
    soundEffectPlaying = soundEffectLaser;
    CurrentWeapon = “Laser”;
    }
    }
    }
    [/code]
  6. Draw the instructions and the name of the current sound effect. Insert the following code to the Draw() method.
    [code]
    spriteBatch.Begin();
    // Draw the instructions
    spriteBatch.DrawString(font, “Tap and hold on for changing
    your” + “weapon.nTap for firing”, new Vector2(0,0), Color.
    White);
    // Draw the current weapon’s name
    spriteBatch.DrawString(font, “Current Weapon: ” +
    CurrentWeapon, new Vector2(0, 70), Color.White);
    spriteBatch.End();
    [/code]
  7. Build and run the application. It should run as shown in the screenshot to the left. When you tap the screen and hold it for a few seconds, the sound effect will be something similar to the screenshot on the right:
    Adding sound effects to your game

How it works…

In step 2, the font will be used to draw the name of the current sound effect and the controlling instructions; the CurrentWeapon indicates the name of the current weapon; soundEffectLaser and soundEffectMachineGun, the SoundEffect instances, individually represent the laser and machine gun sounds; soundEffectPlaying is the currently playing sound effect.

In step 3, we use the Hold gesture to switch the playing sound effect. It is required to enable the gesture type in TouchPanel.

In step 5, the first part is to check whether the user taps on the Windows Phone 7 screen. If so, then play the current sound effect if it is not null. The second part is to switch the sound effect for playing using the Hold gesture. If the on-going gesture is Hold, we will alternate the sound effects between the laser and the machine gun for playing.

Adding stereo sounds to your game

Sometimes, the music and simple sound effects are not enough for you, if you are pursuing the realistic feeling. You cannot determine the place where the sound comes from in your game world. If you have experience of playing Counter-Strike, it is easy to know how many enemies are near you when you stop moving, by listening to the sound. This technique is called Stereo Sound. It uses two or more independent audio channels through a symmetrical configuration of loudspeakers to create the impression of the sound heard from different directions, similar to natural hearing. For the stereo sound, Windows Phone 7 XNA simulates a sound emitter and listener, so that when the position of the emitter is changing, the listener will get a processed sound effect according to the distance between them. In this recipe, you will learn how to use the XNA framework to implement a stereo sound.

Getting ready

In this example, we will use the SoundEffectInstance class with its methods to simulate a 3D sound effect. SoundEffectInstance provides the single playing, paused, and stopped methods to control an instance of sound effect. You can create a SoundEffectInstance by calling the SoundEffect.CreateInstance() method. Initially, the SoundEffectInstance is created as stopped, but you can play it by calling the SoundEffectInstance.Play() method. The volume, panning, and pitch of SoundEffectInstance can be modified by setting the Volume, Pitch, and Pan properties. On Windows Phone 7, a game can have a maximum of 16 total playing SoundEffectInstance instances at one time, combined across all loaded SoundEffect objects. Attempts to play a SoundEffectInstance beyond this limit will fail.

The SoundEffectInstance.Apply3D() method simulates the 3D sound effect. It receives two parameters, the object of AudioEmitter and AudioListener classes. This method will calculate the 3D audio values between an AudioEmitter and an AudioListener object, and will apply the resulting values to the SoundEffectInstance instance. If you want to apply the 3D effect to a SoundEffectInstance, you must call the method before you call the SoundEffectInstance.Play()method. Calling this method automatically sets the Windows Phone 7 speaker mix for any sound played by this SoundEffectInstance to a value calculated by the difference in Position property values between the listener and the emitter. In preparation for the mix, the sound is converted to mono. Any stereo information in this sound is discarded.

How to do it…

The following steps give you a complete guide to implementing a stereo sound effect:

  1. Create a Windows Phone Game named PlayStereoSound and change the Game1. cs to PlayStereoSoundGame.cs. Add the audio file drums.wma and the model file BallLowPoly.fbx to the project content.
  2. Declare the essential variables to the field of the PlayStereoSoundGame class. Add the following code to the class:
    [code]
    // Sound effect object loads the sound effect file
    SoundEffect soundEffect;
    // Instance of a SoundEffect sound.
    SoundEffectInstance soundEffectInstance;
    // AudioEmitter and AudioListener simulate 3D audio effects
    AudioEmitter emitter;
    AudioListener listener;
    // The world position represents the 3D position for
    AudioEmitter
    Vector3 objectPos;
    // A ball for visually presenting the varying AudioEmitter
    // world position.
    Model modelBall;
    Matrix worldBall = Matrix.Identity;
    // Camera
    Vector3 cameraPosition;
    Matrix view;
    Matrix projection;
    [/code]
  3. Initialize the camera, the audio emitter, and the audio listener. Add the following code to the Initialize() method:
    [code]
    // Initialize the camera
    cameraPosition = new Vector3(0, 30, 50);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio,
    1.0f, 1000.0f);
    // Initialize the AudioEmitter and AudioListener
    emitter = new AudioEmitter();
    listener = new AudioListener();
    [/code]
  4. Load the ball model and the drum sound effect. Then, create the instance of the drum sound effect and apply the audio emitter to the audio listener of the instance. Finally, play the sound effect. Add the following code to the LoadContent() method:
    [code]
    // Load the ball model
    modelBall = Content.Load<Model>(“BallLowPoly”);
    // Load the sound effect
    soundEffect = Content.Load<SoundEffect>(“drums”);
    // Create an instance of the sound effect
    soundEffectInstance = soundEffect.CreateInstance();
    // Apply 3D position to the sound effect instance
    soundEffectInstance.Apply3D(listener, emitter);
    soundEffectInstance.IsLooped = true;
    // Play the sound
    soundEffectInstance.Play();
    [/code]
  5. Rotate the audio emitter around the Y axis. Add the following lines to the Update() method:
    [code]
    // Rotate around axis Y
    objectPos = new Vector3(
    (float)Math.Cos(gameTime.TotalGameTime.TotalSeconds) / 2,
    0,
    (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds) /
    2);
    // Update the position of the audio emitter
    emitter.Position = objectPos;
    // Apply the new position of the audio emitter to the audio
    listener
    soundEffectInstance.Apply3D(listener, emitter);
    [/code]
  6. Define the DrawModel() method. Add the following code to the PlayStereoSoundGame class:
    [code]
    // Draw the 3D model
    public void DrawModel(Model model, Matrix world, Matrix view,
    Matrix projection)
    {
    Matrix[] transforms = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(transforms);
    foreach (ModelMesh mesh in model.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.EnableDefaultLighting();
    effect.World = transforms[mesh.ParentBone.Index] *
    world;
    effect.View = view;
    effect.Projection = projection;
    }
    mesh.Draw();
    }
    }
    [/code]
  7. Draw the ball model and rotate it around the Y axis to coincide with the position of the audio emitter. Add the following code to the Draw() method:
    [code]
    // Draw the rotating ball
    DrawModel(modelBall, worldBall *
    Matrix.CreateTranslation(objectPos * 30), view,
    projection);
    [/code]
  8. Build and run the application, and it should run similar to the following screenshots:
    Adding stereo sounds to your game

How it works…

In step 2, the soundEffect will be used to load the sound effect file; the soundEffectInstance plays and applies the 3D sound effect; emitter and listener will combine with each other to simulate the 3D audio effects; objectPos represents the position changes around the Y axis, the latest value will be used to update the position value of the AudioEmitter object; modelBall loads the ball model; worldBall stores the world position of a ball model in 3D; the next three variables cameraPosition, view, and project depict the camera.

In step 4, after loading the ball model sound effect, we create a SoundEffectInstance object using the soundEffect.CreateInstance() method. Note that it is required to call the SoundEffectInstance.Apply3D() method with AudioListener and AudioEmitter objects before the Play() method. If you do not do so, the next time you call the Apply3D() method, it will throw an exception.

In step 5, we compute the objectPos for rotating around the Y axis. The X value comes from the Math.Cos() method; the Z value comes from the Math.Sin(). These two factors are equal to the value of a round in the XZ plain. After that, we use the newly created objectPos to update the position of the emitter and then call the SoundEffectInstance. Apply3D() method to re-calculate the playing 3D sound effect in the surroundings. In step 7, for the world parameter of the DrawModel() method, we use the latest objectPos to update the translation of the ball model in the 3D world. This will make the ball rotate around the Y axis along with the position of the sound effect emitter.

 

Windows Phone Collision Detection #Part 2

Mapping a tapped location to 3D

To pick an object in a 3D game is relevant in terms of real-time strategy. For example, in StarCraft2, you can choose a construction from a 2D panel, then a semi-transparent 3D model will show up in the game view that lets you choose the best location for building the construction. Or, you can select your army by just clicking the left button of the mouse and drawing a rectangle covering the units you want to control. All of these happen between 2D and 3D. This is magic! Actually, this technique maps the clicking position in screen coordinate from 2D to 3D world. In this recipe, you will learn how this important mapping method works in the Windows Phone 7 game.

How to do it…

The following steps will lead you to make your own version of picking an object in a 3D game:

  1. Create the Windows Phone Game project named Pick3DModel, change Game1. cs to Pick3DModelGame.cs and add a new Marker.cs to the project. Then, we create a Content Pipeline Extension Library called ModelVerticesPipeline, replace ContentProcessor1.cs with ModelVerticesPipeline.cs. After that, add the model file BallLowPoly.FBX and image Marker.png to the content project.
  2. Create ModelVerticesProcessor in ModelVerticesProcessor.cs of the ModelVerticesPipeline project. Since the ray-triangle collision detection between ray and model needs the triangle information, in the extension model process, we will extract all of the model vertices and the model global bounding sphere. The returned bounding sphere will serve for the ray-sphere collision detection, before model ray-triangle collision detection, as a performance consideration; the extracted vertices will be used to generate the triangles for the model ray-triangle collision detection when the ray collides with the model bounding sphere. Add the definition of ModelVerticesProcessor class to ModelVerticesProcessor.cs.
  3. ModelVerticesProcessor inherits from the ModelProcessor for extracting extra model vertices. The beginning of the class should be:
    [code]
    publicclass ModelVerticesProcessor : ModelProcessor {. . .}
    [/code]
  4. Add the variable vertices to store the model vertices in the ModelVerticesProcessor class field.
    [code]
    List<Vector3> vertices = new List<Vector3>();
    [/code]
  5. Override the Process()method of the ModelVerticesProcessor class. This is the main method in charge of processing the content. In the method, we extract the model vertices and BoundingSphere, and store them into the ModelContent. Tag property as a Dictionary object.
    [code]
    // Chain to the base ModelProcessor class.
    ModelContent model = base.Process(input, context);
    // Look up the input vertex positions.
    FindVertices(input);
    // Create a dictionary object to store the model vertices and
    // BoundingSphere
    Dictionary<string, object> tagData =
    new Dictionary<string, object>();
    model.Tag = tagData;
    // Store vertex information in the tag data, as an array of
    // Vector3.
    tagData.Add(“Vertices”, vertices.ToArray());
    // Also store a custom bounding sphere.
    tagData.Add(“BoundingSphere”,
    BoundingSphere.CreateFromPoints(vertices));
    return model;
    [/code]
  6. Define the FindVertices() method of the ModelVerticesProcessor class:
    [code]
    // Helper for extracting a list of all the vertex positions in
    // a model.
    void FindVertices(NodeContent node)
    {
    // Convert the current NodeContent to MeshContent if it is
    // a mesh
    MeshContent mesh = node as MeshContent;
    if (mesh != null)
    {
    // Get the absolute transform of the mesh
    Matrix absoluteTransform = mesh.AbsoluteTransform;
    // Iterate every geometry in the mesh
    foreach (GeometryContent geometry in mesh.Geometry)
    {
    // Loop over all the indices in geometry.
    // Every group of three indices represents one
    // triangle.
    foreach (int index in geometry.Indices)
    {
    // Get the vertex position
    Vector3 vertex =
    geometry.Vertices.Positions[index];
    // Transform from local into world space.
    vertex = Vector3.Transform(vertex,
    absoluteTransform);
    // Store this vertex.
    vertices.Add(vertex);
    }
    }
    }
    // Recursively scan over the children of this node.
    foreach (NodeContent child in node.Children)
    {
    FindVertices(child);
    }
    }
    [/code]
  7. Now, build the ModelVerticesPipeline project. You will get the runtime library ModelVerticesProcessor.dll in which the ModelVerticesProcessor stores.
  8. In the next few steps, we will define the Marker class in Marker.cs of the Pick3DModel project.
  9. The Marker class inherits from DrawableGameComponent. Add the variables to the Marker class field:
    [code]
    // SpriteBatch for drawing the marker texture
    SpriteBatch spriteBatch;
    // ContentManager for loading the marker texture
    ContentManager content;
    // Marker texture
    Texture2D texMarker;
    // Texture origin position for moving or rotation
    Vector2 centerTexture;
    // Texture position on screen
    publicVector2 position;
    [/code]
  10. Add the constructor of the Marker class.
    [code]
    public Marker(Game game, ContentManager content)
    : base(game)
    {
    this.content = content;
    }
    [/code]
  11. Implement the LoadContent() method, which will load the marker texture and define the texture origin position.
    [code]
    protected override void LoadContent()
    {
    spriteBatch = new SpriteBatch(GraphicsDevice);
    texMarker = content.Load<Texture2D>(“Marker”);
    centerTexture = new Vector2(texMarker.Width / 2,
    texMarker.Height / 2);
    base.LoadContent();
    }
    [/code]
  12. Let the marker inside the Windows Phone 7 screen. We define the Update() method to achieve this.
    [code]
    // Calculate where the marker’s position is on the screen. The
    // position is clamped to the viewport so that the marker
    // can’t go off the screen.
    publicoverridevoid Update(GameTime gameTime)
    {
    TouchCollection touches = TouchPanel.GetState();
    if (touches.Count > 0 && touches[0].State ==
    TouchLocationState.Pressed)
    {
    position.X = touches[0].Position.X;
    position.Y = touches[0].Position.Y;
    }
    base.Update(gameTime);
    }
    [/code]
  13. Define the CalculateMarkerRay() method that calculates a world space ray starting at the camera’s eye and pointing in the direction of the cursor. The Viewport.Unproject() method is used to accomplish this.
    [code]
    publicRay CalculateMarkerRay(Matrix projectionMatrix,
    Matrix viewMatrix)
    {
    // Create 2 positions in screenspace using the tapped
    // position. 0 is as close as possible to the camera, 1 is
    // as far away as possible.
    Vector3 nearSource = newVector3(position, 0f);
    Vector3 farSource = newVector3(position, 1f);
    // Use Viewport.Unproject to tell what those two screen
    // space positions would be in world space.
    Vector3 nearPoint =
    GraphicsDevice.Viewport.Unproject(nearSource,
    projectionMatrix, viewMatrix, Matrix.Identity);
    Vector3 farPoint =
    GraphicsDevice.Viewport.Unproject(farSource,
    projectionMatrix, viewMatrix, Matrix.Identity);
    // Find the direction vector that goes from the nearPoint
    // to the farPoint and normalize it
    Vector3 direction = farPoint – nearPoint;
    direction.Normalize();
    // Return a new ray using nearPoint as the source.
    returnnewRay(nearPoint, direction);
    }
    [/code]
  14. From this step we begin to compute the ray-model collision and draw the collided triangle and model mesh on Windows Phone 7 in the game main class Pick3DModelGame. Now, insert the lines to the class field as data member:
    [code]
    // Marker Ray
    Ray markerRay;
    // Marker
    Marker marker;
    // Model object and model world position
    Model modelObject;
    Matrix worldModel = Matrix.Identity;
    // Camera view and projection matrices
    Matrix viewMatrix;
    Matrix projectionMatrix;
    // Define the picked triangle vertex array
    VertexPositionColor[] pickedTriangle =
    {
    newVertexPositionColor(Vector3.Zero, Color.Black),
    newVertexPositionColor(Vector3.Zero, Color.Black),
    newVertexPositionColor(Vector3.Zero, Color.Black),
    };
    // Vertex array to represent the selected model
    VertexPositionColor[] verticesModel;
    VertexBuffer vertexBufferModel;
    // The flag indicates whether the ray collides with the model
    float? intersection;
    // The effect of the object is to draw the picked triangle
    BasicEffectwireFrameEffect;
    // The wire frame render state
    staticRasterizerState WireFrame = newRasterizerState
    {
    FillMode = FillMode.WireFrame,
    CullMode = CullMode.None
    };
    [/code]
  15. Initialize the camera, marker, and wireFrameEffect. Add the code to the Initialize() method:
    [code]
    // Intialize the camera
    viewMatrix = Matrix.CreateLookAt(new Vector3(0, 5, 15),
    Vector3.Zero, Vector3.Up);
    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.ToRadians(45.0f),
    GraphicsDevice.Viewport.AspectRatio, .01f, 1000);
    // Initialize the marker
    marker = new Marker(this, Content);
    Components.Add(marker);
    wireFrameEffect = new BasicEffect(graphics.GraphicsDevice);
    [/code]
  16. Load the ball model and read the ball vertices. Then initialize the vertex array of the ball model for drawing the ball mesh on the Windows Phone 7 screen. Insert the following code in to the LoadContent() method:
    [code]
    // Load the ball object
    modelObject = Content.Load<Model>(“BallLowPoly”);
    // Read the vertices
    Dictionary<string, object> tagData =
    (Dictionary<string, object>)modelObject.Tag;
    Vector3[] vertices = (Vector3[])tagData[“Vertices”];
    // Initialize the model vertex array for drawing on screen
    verticesModel = new VertexPositionColor[vertices.Length];
    for (int i = 0; i < vertices.Length; i++)
    {
    verticesModel[i] =
    new VertexPositionColor(vertices[i], Color.Red);
    }
    vertexBufferModel = new VertexBuffer(
    GraphicsDevice, VertexPositionColor.VertexDeclaration,
    vertices.Length, BufferUsage.WriteOnly);
    vertexBufferModel.SetData(verticesModel);
    [/code]
  17. Define the ray-model collision detection method UpdatePicking() in the Pick3DModelGame class.
    [code]
    void UpdatePicking()
    {
    // Look up a collision ray based on the current marker
    // position.
    markerRay = marker.CalculateMarkerRay(projectionMatrix,
    viewMatrix);
    // Keep track of the closest object we have seen so far,
    // so we can choose the closest one if there are several
    // models under the cursor.
    float closestIntersection = float.MaxValue;
    317
    Vector3 vertex1, vertex2, vertex3;
    // Perform the ray to model intersection test.
    intersection = RayIntersectsModel(markerRay, modelObject,
    worldModel, out vertex1, out vertex2,out vertex3);
    // Check whether the ray-model collistion happens
    if (intersection != null)
    {
    // If so, is it closer than any other model we might
    // have previously intersected?
    if (intersection < closestIntersection)
    {
    // Store information about this model.
    closestIntersection = intersection.Value;
    // Store vertex positions so we can display the
    // picked triangle.
    pickedTriangle[0].Position = vertex1;
    pickedTriangle[1].Position = vertex2;
    pickedTriangle[2].Position = vertex3;
    }
    }
    }
    [/code]
  18. Define the RayIntersectsModel() method in the Pick3DModelGame class:
    [code]
    float? RayIntersectsModel(Ray ray, Model model, Matrix
    modelTransform, out Vector3 vertex1, out Vector3 vertex2,
    out Vector3 vertex3)
    {
    bool insideBoundingSphere;
    vertex1 = vertex2 = vertex3 = Vector3.Zero;
    Matrix inverseTransform = Matrix.Invert(modelTransform);
    ray.Position = Vector3.Transform(ray.Position,
    inverseTransform);
    ray.Direction = Vector3.TransformNormal(ray.Direction,
    inverseTransform);
    // Look up our custom collision data from the Tag property
    // of the model.
    Dictionary<string, object> tagData =
    (Dictionary<string, object>)model.Tag;
    BoundingSphere boundingSphere =
    (BoundingSphere)tagData[“BoundingSphere”];
    if (boundingSphere.Intersects(ray) == null)
    {
    // If the ray does not intersect the bounding sphere,
    // there is no need to do the the ray-triangle
    // collision detection
    insideBoundingSphere = false;
    return null;
    }
    else
    {
    // The bounding sphere test passed, do the ray-
    // triangle test
    insideBoundingSphere = true;
    // Keep track of the closest triangle we found so far,
    // so we can always return the closest one.
    float? closestIntersection = null;
    // Loop over the vertex data, 3 at a time for a
    // triangle
    Vector3[] vertices = (Vector3[])tagData[“Vertices”];
    for (int i = 0; i < vertices.Length; i += 3)
    {
    // Perform a ray to triangle intersection test.
    float? intersection;
    RayIntersectsTriangle(ref ray,
    ref vertices[i],
    ref vertices[i + 1],
    ref vertices[i + 2],
    out intersection);
    // Does the ray intersect this triangle?
    if (intersection != null)
    {
    // If so, find the closest one
    if ((closestIntersection == null) ||
    (intersection < closestIntersection))
    {
    // Store the distance to this triangle.
    closestIntersection = intersection;
    // Transform the three vertex positions
    // into world space, and store them into
    // the output vertex parameters.
    Vector3.Transform(ref vertices[i],
    ref modelTransform, out vertex1);
    Vector3.Transform(ref vertices[i + 1],
    ref modelTransform, out vertex2);
    Vector3.Transform(ref vertices[i + 2],
    ref modelTransform, out vertex3);
    }
    }
    }
    return closestIntersection;
    }
    }
    [/code]
  19. Draw the ball on the Windows Phone 7 screen with the model heighted wireframe and the picked triangle. Add the following code to the Draw() method:
    [code]
    GraphicsDevice.BlendState = BlendState.Opaque;
    GraphicsDevice.DepthStencilState = DepthStencilState.Default;
    // Draw model
    DrawModel(modelObject, worldModel);
    // Draw the model wire frame
    DrawPickedWireFrameModel();
    // Draw the outline of the triangle under the cursor.
    DrawPickedTriangle();
    [/code]
  20. Now we should give the definitions of the called methods:
    [code]
    DrawPickedWireFrameModel(), DrawPickedTriangle(), and DrawModel().
    [/code]
  21. Define the DrawPickedWireFrameModel() method in the Pick3DModelGame class:
    [code]
    void DrawPickedWireFrameModel()
    {
    if (intersection != null)
    {
    GraphicsDevice device = graphics.GraphicsDevice;
    device.RasterizerState = WireFrame;
    device.DepthStencilState = DepthStencilState.None;
    // Activate the line drawing BasicEffect.
    wireFrameEffect.Projection = projectionMatrix;
    wireFrameEffect.View = viewMatrix;
    wireFrameEffect.CurrentTechnique.Passes[0].Apply();
    // Draw the triangle.
    device.DrawUserPrimitives(PrimitiveType.TriangleList,
    verticesModel, 0, verticesModel.Length / 3);
    // Reset renderstates to their default values.
    device.RasterizerState =
    RasterizerState.CullCounterClockwise;
    device.DepthStencilState = DepthStencilState.Default;
    }
    }
    [/code]
  22. Implement the DrawPickedTriangle() method in the Pick3DModelGame class:
    [ocde]
    void DrawPickedTriangle()
    {
    if (intersection != null)
    {
    GraphicsDevice device = graphics.GraphicsDevice;
    // Set line drawing renderstates. We disable backface
    // culling and turn off the depth buffer because we
    // want to be able to see the picked triangle outline
    // regardless of which way it is facing, and even if
    // there is other geometry in front of it.
    device.RasterizerState = WireFrame;
    device.DepthStencilState = DepthStencilState.None;
    // Activate the line drawing BasicEffect.
    wireFrameEffect.Projection = projectionMatrix;
    wireFrameEffect.View = viewMatrix;
    wireFrameEffect.VertexColorEnabled = true;
    wireFrameEffect.CurrentTechnique.Passes[0].Apply();
    // Draw the triangle.
    device.DrawUserPrimitives(PrimitiveType.TriangleList,
    pickedTriangle, 0, 1);
    // Reset renderstates to their default values.
    device.RasterizerState =
    RasterizerState.CullCounterClockwise;
    device.DepthStencilState = DepthStencilState.Default;
    }
    }
    [/code]
  23. Give the definition of the DrawModel() method in the Pick3DModelGame class:
    [code]
    private void DrawModel(Model model, Matrix worldTransform)
    {
    Matrix[] transforms = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(transforms);
    foreach (ModelMesh mesh in model.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.EnableDefaultLighting();
    effect.PreferPerPixelLighting = true;
    effect.View = viewMatrix;
    effect.Projection = projectionMatrix;
    effect.World = transforms[mesh.ParentBone.Index] *
    worldTransform;
    }
    mesh.Draw();
    }
    }
    [/code]
  24. Now, build and run the application. It should run as shown in the following screenshots:
    Mapping a tapped location

How it works…

In step 5, after processing the model basic information as usual in the base class, we call the FindVertices()method to get all of the model vertices. After that, the dictionary object tagData will receive the vertices information and the generated BoundingSphere from the model vertices, the tagData will be assigned to ModelContent.Tag for the game application to read the model vertices and BoundingSphere from the model XNB file.

In step 6, the first line is to convert the current NodeContent to MeshContent if the current ModelContent holds a model mesh and not a bone or other types. If mesh, an object of MeshContent, is not null, we begin to extract its vertices. First of all, the code reads the mesh.AbsoluteTransform for transforming the model vertices from object coordinate to world coordinate. Then, we iterate the geometry of the current mesh to get the vertices. In the loop for looping over each of the vertices, we use the Vector3.Transform() with absoluteTransform matrix to actually transform the vertex from object coordinate to world. After that, the transformed vertex will be saved to the vertices collection. When all of the vertices of the current mesh are processed, the code will deal with the current child content for retrieving the vertices.

In step 8, the spriteBatch is the main object in charge of rendering the texture on the Windows Phone 7 screen; the content object of ContentManager manages the game contents; texMarker represents the marker texture; the centerTexture specifies the origin point of texture for rotating and moving; the variable position holds the texture position on screen.

In step 10, the constructor receives the Game and ContentManager objects. The game object provides GraphicsDevice and the content offers access to the texture file.

In step 13, this is the key method to generate the ray from the screen coordinates to the world coordinates. The nearSource is used for generating the closest point to the camera; farSource is for the point that is far away. Then, call the Viewport.Unproject() method to generate the nearPoint and farPoint. After that, convert the nearSource and farSource from screen space to the nearPoint and farPoint in world space. Next, use the unprojected points farPoint and nearPoint to compute the ray direction. Finally, return the new ray object with the nearPoint and normalized direction.

In step 14, the markerRay specifies the ray from the tapped position to world space; marker is the visual sign on screen that indicates the start point of markerRay; modelObject will load the model; worldModel stands for the transformation matrix of modelObject; the view and projection will be used to initialize the camera and help generate the markerRay; pickedTriangle is the triangle vertex array which will be used to draw the triangle on the model where it collides with the markerRay; the verticesModel reads and stores all of the model vertices and will serve the picked model draw in wireframe; intersection indicates the collision state. If not null, the value is the distance between the intersection point and the markerRay start point. The final WireFrame defines the device render state.

Implementing sphere-triangle collision detection

In FPS game, when the character moves forward to a building or a wall and contacts the object, it will stop and stand there. And you know there is no object around you, because the camera is your eye in the FPS game. If you wonder how the game developers achieve this, you will find the answer in this recipe.

How to do it…

The following steps will show you the best practice of applying the sphere-triangle collision detection for first-person perspective camera:

  1. Create a Windows Phone Game project named CameraModelCollision, change Game1.cs to CameraModelCollisionGame.cs. Meanwhile, add Triangle. cs and TriangleSphereCollisionDetection.cs to the project. Then, create a Content Pipeline Extension Library project named MeshVerticesProcessor and replace the ContentProcessor1.cs with MeshVerticesProcessor.cs. After that, insert the 3D model file BigBox.fbx and sprite font file gameFont. spriteFont to the content project.
  2. Define the MeshVerticesProcessor class in MeshVerticesProcessor.cs of MeshVerticesProcessor project. The class is the same as the processor defined in the Implementing BoundingSphere collision detection in a 3D game recipe.
  3. Implement the Triangle class in Triangle.cs in the CameraModelCollision project.
    Declare the necessary data members of the Triangle class. Add the following lines to the class field:
    [code]
    // The triangle corners
    public Vector3 A;
    public Vector3 B;
    public Vector3 C;
    [/code]
  4. Define the constructors for the class:
    [code]
    // Constructor
    public Triangle()
    {
    A = Vector3.Zero;
    B = Vector3.Zero;
    C = Vector3.Zero;
    }
    // Constructor
    public Triangle(Vector3 v0, Vector3 v1, Vector3 v2)
    {
    A = v0;
    B = v1;
    C = v2;
    }
    [/code]
  5. Implement the Normal class of the Triangle class. This method returns a unit length normal vector perpendicular to the plane of the triangle.
    [code]
    public void Normal(outVector3 normal)
    {
    normal = Vector3.Zero;
    Vector3 side1 = B – A;
    Vector3 side2 = C – A;
    normal = Vector3.Normalize(Vector3.Cross(side1, side2));
    }
    [/code]
  6. Define the InverseNormal() method of the Triangle class. This method gets a normal that faces away from the point specified (faces in).
    [code]
    // Get a normal that faces away from the point specified // (faces in) public void InverseNormal(ref Vector3 point, out Vector3 inverseNormal) { Normal(out inverseNormal); // The direction from any corner of the triangle to the //point Vector3 inverseDirection = point – A; // Roughly facing the same way
    if (Vector3.Dot(inverseNormal, inverseDirection) > 0)
    {
    // Same direction therefore invert the normal to face
    // away from the direction to face the point
    Vector3.Multiply(ref inverseNormal, -1.0f,
    out inverseNormal);
    }
    }
    [/code]
  7. Create the TriangleSphereCollisionDetection class. This class contains the methods to take the triangle sphere collision detection.
    Define the IsSphereCollideWithTringles() method. This method is the root method that kicks off the sphere triangle collision detection:
    [code]
    public static bool IsSphereCollideWithTringles(
    List<Vector3> vertices,
    BoundingSphere boundingSphere, out Triangle triangle)
    {
    bool result = false;
    triangle = null;
    for (int i = 0; i < vertices.Count; i += 3)
    {
    // Create triangle from the tree vertices
    Triangle t = new Triangle(vertices[i], vertices[i + 1],
    vertices[i + 2]);
    // Check if the sphere collides with the triangle
    result = SphereTriangleCollision(ref boundingSphere,
    ref t);
    if (result)
    {
    triangle = t;
    return result;
    }
    }
    return result;
    }
    [/code]
  8. Implement the SphereTriangleCollision() method. This method will generate a ray from the center of the sphere and perform the ray-triangle collision check:
    [code]
    private static bool SphereTriangleCollision(
    ref BoundingSphere sphere, ref Triangle triangle)
    {
    Ray ray = new Ray();
    ray.Position = sphere.Center;
    // Create a vector facing towards the triangle from the
    // ray starting point.
    Vector3 inverseNormal;
    triangle.InverseNormal(
    ref ray.Position, out inverseNormal);
    ray.Direction = inverseNormal;
    // Check if the ray hits the triangle
    float? distance = RayTriangleIntersects(ref ray,
    ref triangle);
    if (distance != null && distance > 0 &&
    distance <= sphere.Radius)
    {
    // Hit the surface of the triangle
    return true;
    }
    return false;
    }
    [/code]
  9. Give the definition of RayTriangleIntersects() to the TriangleSphereCollisionDetection class. This is the method that performs the ray-triangle collision detection and returns a distance value if the collision takes place:
    [code]
    public static float? RayTriangleIntersects(ref Ray ray, ref
    Triangle triangle)
    {
    float? result;
    RayIntersectsTriangle(ref ray, ref triangle.A,
    ref triangle.B, ref triangle.C, out result);
    return result;
    }
    [/code]
  10. Add MeshVerticesProcessor.dll to the content project reference list, and change the processor of BigBox.FBX to MeshVerticesProcessor, as shown in the following screenshot:
    the processor of BigBox.FBX to MeshVerticesProcessor
  11. From this step, we will begin to take the real-time collision between the camera bounding sphere and the model in the main game project CameraModelCollision. Add the code to the CameraModelCollision class field:
    [code]
    // SpriteFont for showing instructions
    SpriteFont font;
    // Box model
    Model modelBox;
    // Box model world transformation
    Matrix worldBox = Matrix.Identity;
    // Camera position and look at target
    Vector3 cameraPosition;
    Vector3 targetOffset;
    // Camera view and projection matrices
    public Matrix view;
    public Matrix projection;
    // Camera BoundingSphere
    BoundingSphere boundingSphereCamera;
    // Vertices of Box Model
    List<Vector3> verticesBox;
    // Collided triangle
    Triangle triangleCollided;
    // Normal of collided triangle
    Vector3 normalTriangle;
    // The moving forward flag
    bool ForwardCollide;
    bool BackwardCollide;
    // The top and bottom hit regions on screen
    Rectangle TopHitRegion;
    Rectangle BottomHitRegion;
    [/code]
  12. Initialize the camera and hit regions. Add the code to the Initialize() method in the CameraModelCollision class:
    [code]
    // Initialize camera
    cameraPosition = new Vector3(0, 5, 50);
    targetOffset = new Vector3(0, 0, -1000);
    view = Matrix.CreateLookAt(cameraPosition, targetOffset,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio,
    0.1f, 1000.0f);
    // Initialize the top and bottom hit regions
    Viewport viewport = GraphicsDevice.Viewport;
    TopHitRegion = new Rectangle(0, 0, viewport.Width,
    viewport.Height / 2);
    BottomHitRegion = new Rectangle(0, viewport.Height / 2,
    viewport.Width, viewport.Height / 2);
    [/code]
  13. Load the box model and initialize the camera bounding sphere. Insert the following code into the LoadContent() method in the CameraModelCollision class:
    [code]
    // Load the game font font = Content.Load<SpriteFont>(“gameFont”); // Load the box model modelBox = Content.Load<Model>(“BigBox”);
    // Get the vertex collection of box model
    verticesBox = ((Dictionary<string,
    List<Vector3>>)modelBox.Tag)[“Box001”];
    // Create the BoundingSphere of camera
    boundingSphereCamera = new BoundingSphere(cameraPosition, 5);
    [/code]
  14. Move the camera and take camera-sphere collision detection. Insert the code into the Update()method in the CameraModelCollision class.
    [code]
    // Check whether the tapped position is inside the TopHitRegion
    // or BottomHitRegion
    TouchCollection touches = TouchPanel.GetState();
    if (touches.Count > 0 && touches[0].State ==
    TouchLocationState.Pressed)
    {
    Point point = new Point((int)touches[0].Position.X,
    (int)touches[0].Position.Y);
    if (TopHitRegion.Contains(point))
    {
    if (!ForwardCollide)
    {
    // If the tapped position is within the
    // TopHitRegion and the camera has not collided
    // with the model, move the camera forward
    view.Translation += new Vector3(0, 0, 1);
    }
    }
    if (BottomHitRegion.Contains(point))
    {
    // If the tapped position is within the
    // BottomHitRegion and the camera has not
    // collided with the model, move the camera
    // backward
    if (!BackwardCollide)
    {
    view.Translation -= new Vector3(0, 0, 1);
    }
    }
    }
    // Update the center position of camera bounding sphere
    boundingSphereCamera.Center = view.Translation;
    // Detect the collision between camera bounding sphere and
    // model triangles
    TriangleSphereCollisionDetection.IsSphereCollideWithTriangles(
    verticesBox, boundingSphereCamera,
    out triangleCollided);
    // If the collision happens, the collided triangle
    // is not null
    if (triangleCollided != null)
    {
    // Get the normal of the collided triangle
    triangleCollided.Normal(out normalTriangle);
    // Get the direction from the center of camera
    // BoundingSphere to the collided triangle
    Vector3 Direction = view.Translation – triangleCollided.A;
    // If the camera faces the model, the dot
    // product between the triangle normal
    // and direction is less than 0
    float directionChecker =
    Vector3.Dot(normalTriangle, Direction);
    if (directionChecker < 0)
    {
    ForwardCollide = true;
    }
    }
    else
    {
    ForwardCollide = false;
    }
    [/code]
  15. Define the DrawModel() method in the CameraModelCollision class to draw the 3D model.
    [code]
    // Draw model
    public void DrawModel(Model model, Matrix world, Matrix view,
    Matrix projection)
    {
    Matrix[] transforms = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(transforms);
    foreach (ModelMesh mesh in model.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.PreferPerPixelLighting = true;
    effect.EnableDefaultLighting();
    effect.DiffuseColor = Color.White.ToVector3();
    effect.World = transforms[mesh.ParentBone.Index] *
    world;
    effect.View = view;
    effect.Projection = projection;
    }
    mesh.Draw();
    }
    }
    [/code]
  16. Draw the model and instructions on the Windows Phone 7 screen. Add the code to the Draw() method:
    [code]
    // Draw the box model
    DrawModel(modelBox, worldBox, view, projection);
    // Draw the instructions
    spriteBatch.Begin();
    spriteBatch.DrawString(font, “1.Tap the top half of screen”
    + “for moving the camera forwardn2.Tap the bottom half”
    + “of” screen for moving the camera backward.”,
    new Vector2(0, 0), Color.White);
    spriteBatch.End();
    [/code]
  17. Now, build and run the application. It should run as shown in the following screenshots:
    sphere-triangle

How it works…

In step 3, A, B, and C represent the three corners of a triangle; you can use them to calculate the triangle edges.

In step 5, first we calculate the two edges of the triangle. Then we use the Vector3. Cross() method to get the normal vector and the Vector3.Normalize() method to normalize the normal vector to a unit length vector.

In step 6, first we get the normal of the triangle. Then, calculate the direction from the triangle corner A to the point outside the triangle. After that, we examine the return value of the Vector3.Dot() method between the triangle normal vector and the direction from the triangle to the outside point. If the dot product is greater than 0, this means the two vectors are in the same direction or on the same side.

In step 7, this method goes through all of the vertices of a model and creates a triangle in every three vertices. With the triangle t and the given boundingSphere, it calls the SphereTriangleCollision() method to take the sphere triangle collision detection. If the result is true, it means the sphere triangle collision happens and the collided triangle will be returned. If not true, the method return value will be false and the triangle t will be null.

In step 8, the first line is to initialize a ray object with the original information. Then, we assign the translation of the sphere center to the ray.Position. After that, we use the Triangle. InverseNormal() method for getting the direction from the point to the current triangle. Now, the ray is ready, the next part is to take the core ray triangle collision detection using the RayTriangleIntersects() method. If the returned distance is not null, greater than zero and less than the radius of the given bounding sphere, a ray triangle collision happens. The method will return true to the caller.

In step 9, insert the definition of the inner RayIntersectsTriangle() method to the class, which we had discussed in the Implementing ray-triangle collision detection recipe in this chapter. Refer to the recipe for a detailed explanation.

In step 11, the font is responsible for showing the instructions; the modelBox loads the box model; worldBox stands for the transformation of the box model; the following four variables cameraPosition, targetOffset, view, and projection are used to initialize the camera; boundingSphereCamera is the bounding sphere around the camera; verticesBox holds the vertices of the box model; triangleCollided specifies the triangle when sphere-triangle collision happens; normalTriangle stores the normal vector of the collided triangle; ForwardCollide and BackwardCollide show that the camera is moving forward or backward; TopHitRegion and BottomHitRegion are the hit regions if you want to move the camera forward or backward.

In step 12, the camera target is -1000 at the Z-axis for realistic viewing when you move the camera. TopHitRegion occupies the top half of the screen; BottomHitRegion takes up the bottom half of the screen.

In step 13, after loading the box model and getting its vertices, we initialize the boundingSphereCamera with a radius of about five units at the camera position.

In step 14, the first part is to check whether the tapped position is inside the TopHitRegion or BottomHitRegion to move the camera forward or backward. After that, we should update the position of the camera bounding sphere, as this is important for us to take the collision detection between camera bounding sphere and model triangles. In the next line, we call the TriangleSphereCollisionDetection.IsSphereCollideWithTriangles() method to detect the collision detection. If the returned triangle is not null, we will calculate the dot product between the camera ray direction and the normal of the collided triangle. If it is less than zero, it means the camera is moving forward, otherwise, it is moving backward.

Making a 3D ball move along a curved surface

No doubt, the real modern 3D games are much more complex; they are not a simple ball or a box with a few triangles. Thousands of polygons for games is common, millions is not unheard of. As a technique, the differences in how to do collision detection between different shape objects are not that much. You should already know the core concept or idea behind how to do it. In this recipe, you will learn the idea of dealing with collisions between models of different shapes.

How to do it…

The following steps will show you how to perform collision detection between a ball and a curved surface:

  1. Create a Windows Phone Game project named BallCollideWithCurve, change Game1.cs to BallCollideWithCurveGame.cs. Then, add triangle.cs and TriangleSphereCollisionDetection.cs to the project. Next, add the Content Pipeline Extension Project named MeshVerticesProcessor, replace the ContentProcessor1.cs with MeshVerticesProcessor.cs. After that, insert the model file ball.FBX and CurveSurface.FBX to the content project.
  2. Define the MeshVerticesProcessor in MeshVerticesProcessor.cs of the MeshVerticesProcessor project. The class definition is the same as the class in the Implementing BoundingBox collision detection in a 3D game recipe in this chapter. For the full explanation, please refer to that recipe.
  3. Define Triangle in Triangle.cs and TriangleSphereCollisionDetection in TriangleSphereCollisionDetection.cs of the CameraModelCollision project. The two class definitions are the same as the classes implemented in the last Implementing sphere-triangle collision detection recipe in this chapter. For a full explanation, please take a look at that recipe.
  4. Change the processor of ball.FBX and CurveSurface.FBX in content project, as shown in the following screenshot:
    ball.FBX and CurveSurface.FBX
  5. Now it is time to draw the ball and curve surface models on screen and take the collision detection in the main game project BallCollideWithCurve. First, add the following lines to the class field:
    [code]
    // Ball model and the world transformation matrix
    Model modelBall;
    Matrix worldBall = Matrix.Identity;
    // Curve model and the world transformation matrix
    Model modelSurface;
    Matrix worldSurface = Matrix.Identity;
    // Camera
    Vector3 cameraPosition;
    publicMatrix view;
    publicMatrix projection;
    // The bounding sphere of ball model
    BoundingSphere boundingSphereBall;
    // The vertices of curve model
    List<Vector3>verticesCurveSurface;
    // Collided triangle
    Triangle CollidedTriangle;
    // The velocity of ball model
    Vector3 Velocity = Vector3.Zero;
    // The acceleration factor
    Vector3 Acceleration = newVector3(0, 0.0098f, 0);
    [/code]
  6. Initialize the camera and the collided triangle. Insert the following code into the Initialize() method:
    [code]
    // Initialize the camera
    cameraPosition = new Vector3(0, 0, 20);
    view = Matrix.CreateLookAt(cameraPosition, Vector3.Zero,
    Vector3.Up);
    projection = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.PiOver4, GraphicsDevice.Viewport.AspectRatio,
    0.1f, 1000.0f);
    // Initialize the collided triangle
    CollidedTriangle = new Triangle();
    [/code]
  7. Load the ball and curve surface models and extract their vertices. Then, create the bounding sphere of the ball model from the extracted vertices.
    [code]
    modelBall = Content.Load<Model>(“Ball”);
    modelSurface = Content.Load<Model>(“CurveSurface”);
    worldBall = Matrix.CreateTranslation(new Vector3(-2, 5, 0));
    Dictionary<string, List<Vector3>> o =
    (Dictionary<string, List<Vector3>>)modelBall.Tag;
    boundingSphereBall =
    BoundingSphere.CreateFromPoints(o[“Sphere001”]);
    boundingSphereBall.Center = worldBall.Translation;
    verticesCurveSurface = ((Dictionary<string, List<Vector3>>)
    modelSurface.Tag)[“Tube001”];
    [/code]
  8. Take the sphere-triangle collision and update the position of the ball model and its bounding sphere. Insert the following code into the Update() method:
    [code]
    // Take the sphere triangle collision detection
    TriangleSphereCollisionDetection.IsSphereCollideWithTriangles(
    verticesCurveSurface, boundingSphereBall,
    out CollidedTriangle);
    float elapsed;
    // If no collision happens, move the ball
    if (CollidedTriangle == null)
    {
    elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
    Velocity += -Acceleration * elapsed;
    worldBall.Translation += Velocity;
    }
    // Update the translation of ball bounding sphere
    boundingSphereBall.Center = worldBall.Translation;
    [/code]
  9. Define the DrawModel() method to draw the model:
    [code]
    public void DrawModel(Model model, Matrix world, Matrix view,
    Matrix projection)
    {
    Matrix[] transforms = new Matrix[model.Bones.Count];
    model.CopyAbsoluteBoneTransformsTo(transforms);
    foreach (ModelMesh mesh in model.Meshes)
    {
    foreach (BasicEffect effect in mesh.Effects)
    {
    effect.PreferPerPixelLighting = true;
    effect.EnableDefaultLighting();
    effect.DiffuseColor = Color.White.ToVector3();
    effect.World = transforms[mesh.ParentBone.Index] *
    world;
    effect.View = view;
    effect.Projection = projection;
    }
    mesh.Draw();
    }
    }
    [/code]
  10. Draw the ball model and curve surface ball on the Windows Phone 7 screen. Paste the following code into the Draw() method:
    [code]
    GraphicsDevice.DepthStencilState = DepthStencilState.Default;
    // Draw the ball model and surface model
    DrawModel(modelBall, worldBall, view, projection);
    DrawModel(modelSurface, worldSurface, view, projection);
    [/code]
  11. Now, build and run the application. The application runs as shown in the following screenshots:
    3D ball move along a curved surface

How it works…

In step 5, the modelBall loads the ball model object; worldBall specifies world transformation of the ball model. Similarly, modelSurface for curve surface model, worldSurface for its world matrix; the next three variables cameraPosition, view, and projection serve for the camera; boundingSphereBall is the bounding sphere around the ball model; verticesCurveSurface is a vertex collection of the curve surface model; CollidedTriangle stores the collided triangle when the ball bounding sphere collides with the curve surface model triangles; Velocity specifies the ball moving velocity; Acceleration defines how the velocity will be changed.

In step 7, we use the BoundingSphere.CreateFromPoints() method to create the bounding sphere of the ball model using the vertices extracted from the Tag property of its model file. For verticesCurveSurface, we just read the vertex collection from its model file.

In step 8, the first line is to detect collision between ball bounding sphere and the triangles of the curve surface model. If the collision happens, CollidedTriangle is not null. At this moment, we start to move the ball. Anytime, it is required that updating the center position of the ball bounding sphere along with the ball model.