## 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;
}
{
float dist = Distance(A, B);
}
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]

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 MassiveObject(ContentManager content,
SpriteBatch spriteBatch)
: base(content, spriteBatch)
{
name = “object”;
mass = 1.0f;
acceleration = Vector2.Zero;
angle = 0.0f;
captured = false;
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.

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;
List<MassiveObject> objects;
public PlayingModule(Game1 game)
{
this.game = game;
rand = new Random();
startTime = 0;
}
{
background = new Sprite(game.Content, game.spriteBatch);
background.origin = Vector2.Zero;
blackHole = new MassiveObject(game.Content, game.spriteBatch);
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.position = new Vector2(200, 240);
ship.mass = 100f;
ship.scale = 0.2f;
}
[/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.”

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;
obj.size.X, 40))
{
obj.alive = false;
energy += obj.scale;
}
}
if (!obj.captured)
{
//attract when object is near the black hole
blackHole.position, 10, 500))
{
obj.Attract(blackHole);
obj.Attract(superCore);
//is object touching the outer edges of the black hole?
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!
superCore.position, 16, 60))
{
obj.captured = true;
obj.startTime = (int)
gameTime.TotalGameTime.TotalMilliseconds;
OrbitalMovement anim1 = new OrbitalMovement(
blackHole.position, 10 + rand.Next(40),
obj.rotation, -0.8f);
}
}
else
{
obj.color = Color.White;
}
}
}
//when captured, time runs out
{
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
64, 40))
{
ship.captured = true;
ship.startTime = (int)
gameTime.TotalGameTime.TotalMilliseconds;
OrbitalMovement anim1 = new OrbitalMovement(
blackHole.position, 10 + rand.Next(40),
ship.rotation, -0.8f);
}
//done being squished?
{
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();
}
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.columns = 8;
obj.totalFrames = 64;
obj.scale = 0.1f + (float)rand.NextDouble();
obj.size = new Vector2(60, 60);
//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.name = “asteroid”;
}
public void CreateSatellite()
{
MassiveObject obj;
obj = new MassiveObject(game.Content, game.spriteBatch);
obj.position = ship.position;
obj.mass = 1;
obj.scale = 0.5f;
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);
energy -= 1;
}
}
[/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.

## Windows Phone Game User Interface, Heads Up Display (HUD) #Part 2

When playing a game, especially for some big games, at the initialization phase, a progress bar will show you the game object loading status and percents. As a time-based game, the progress bar represents the remaining time. Moreover, a Role Playing Game (RPG) often uses the progress bar to present the current life value. A progress bar is a very common control in game development and is easy to use. In this recipe, you will find the inner code for creating a progress bar.

In Windows Phone 7 XNA programming, two methods will let you create the progress bar. One is using the rectangle for drawing the background and forefront. This is simple but not flexible and stylish. If you want to make some innovative and unusual visual effects, the primitives will not meet your needs. The second method will give you much more space to realize your idea for the progress bar. You can use graphic design tool to draw the background and forefront images as you like, then render these images and change the size of the forefront image to comply with the on going percents; even the round or other shapes can be used for presenting the progress status. In this example, we will use the rectangle images (second method) for implementing the progress bar in Windows Phone 7.

How to do it…

The following steps give you a complete guidance to develop a progress bar in your Windows Phone 7 game:

1. Create a Windows Phone Game project in Visual Studio 2010 named ProgressBar, change Game1.cs to ProgressBarGame.cs and insert a ProgressBar.cs in the project. Then add ProgressBarBackground.png and ProgressBarForefront. png to the content project.
2. Add a ProgressBar class in ProgressBar.cs to the main project. Add the code to the ProgressBar class fields:
[code]
// SpriteBatch for drawing 2D image
SpriteBatch spriteBatch;
// ProgressBar forefront and background images
Texture2D texForefront;
Texture2D texBackground;
// The background and forefront positon
Vector2 backgroundPosition;
Vector2 forefrontPosition;
// The offset of forefront image from the background.
float forefrontStartOffSetX;
float forefrontStartOffSetY;
// Current value of progressbar
public int Value;
// The Min and Max values of progressbar
public int Min;
public int Max;
// Percent of current value around 100
float percent;
// the actual rendering width of forefront image
float actualWidth;
// The direction of progress.
bool increase = false;
[/code]
3. Next, we define the Increase property:
[code]
// The increasing direction
public bool Increase
{
get
{
return increase;
}
set
{
// When increasing, the Value begins from Min
if (value)
{
increase = value;
Value = Min;
}
// When decreasing, the Value begins from Max
else
{
increase = value;
Value = Max;
}
}
}
[/code]
4. The next step is to define the constructor of the ProgressBar class:
[code]
public ProgressBar(Vector2 position, Texture2D forefront,
Texture2D background, SpriteBatch spriteBatch)
{
this.spriteBatch = spriteBatch;
texForefront = forefront;
texBackground = background;
backgroundPosition = position;
// Calculate the offset for forefront image
forefrontStartOffSetX = (texBackground.Width –
texForefront.Width) / 2;
forefrontStartOffSetY = (texBackground.Height –
texForefront.Height) / 2;
// Create the forefront image position
forefrontPosition = new Vector2(backgroundPosition.X +
forefrontStartOffSetX,
backgroundPosition.Y + forefrontStartOffSetY);
// Intitialize the Min and Max
Min = 0;
Max = 100;
// Set the increasing direction from high to low.
Increase = false;
}
[/code]
5. After the constructor, the following method definition is the Update(), so add the method to the ProgressBar class:
[code]
public void Update(GameTime gameTime)
{
// If decreasing and Value greater than Min, minus the
// Value by one
if (Increase && Value < Max)
{
Value++;
}
else if (Value > Min)
{
Value–;
}
// Compute the actual forefront image for drawing
percent = (float)Value / 100;
actualWidth = percent * texForefront.Width;
}
[/code]
6. The final step of creating the ProgressBar class is to define the Draw() method:
[code]
public void Draw()
{
spriteBatch.Draw(texBackground, backgroundPosition,
Color.White);
spriteBatch.Draw(texForefront, forefrontPosition, new
Rectangle(0, 0, (int)actualWidth,
texForefront.Height), Color.White);
}
[/code]
7. Use the ProgressBar class in our game. First, add the code to the class field:
[code]
// Texture objects for background and forefront images
Texture2D texForefront;
Texture2D texBackground;
// The background image position
Vector2 position;
// Progress bar object
ProgressBar progressBar;
[/code]
8. Then insert the initialization code to the LoadContent() method:
[code]
// Load the background and forefront images
texForefront =
texBackground =
// Initialize the progress bar
position = new Vector2(200, 240);
progressBar = new ProgressBar(position, texForefront,
texBackground, spriteBatch);
[/code]
9. Next, insert the code to the Update() method:
[code]
// Update the progress bar
progressBar.Update(gameTime);
[/code]
10. [code]
// draw the progress bar
spriteBatch.Begin();
progressBar.Draw();
spriteBatch.End();
[/code]
11. Now, build and run the application, and it will run as shown in the following screenshots:

How it works…

In step 2, the texForefront and texBackground are the Texture2D objects that hold the progressBar forefront and background images. The next two variables forefrontStartOffSetX and forefrontStartOffSetY indicate the offset position of forefront from the background; Value stores the progressBar current value; the Min and Max defines the range of the progressBar; percent and actualWidth will be used to calculate and store the current width of the forefront image respectively; the last variable increase represents the direction of the progressBar value increasing.

In step 3, if the Increase value is false, which means it is decreasing, the Value begins from the right with Max. Otherwise, the Value will begin from the left.

In step 4, notice the computation for forefront image offset, we use the background image width minus the width of the forefront image, get the gap between the left sides of the two images, then use the gap value and divide it by 2, get the offset on the X-axis from the background for the forefront image. The offset on the Y-axis is similar. After getting the offset of the forefront image, we set Min to 0 and Max to 100—the value range of progressBar. The last line is to define the increasing direction. False, here, stands for the progress value that will decrease from 100 to 0, right to left.

In step 5, the first part of the Update() method is to change Value by one, according to the increasing direction. The second part is about computing the actual width of the forefront image for rendering.

In step 6, this code draws the background image and forefront image on screen. Notice the third parameter in the Drawing() method for the forefront image. This is a Rectangle parameter, which represents the part of the forefront image for rendering in every frame; it helps you to adjust the size of the forefront image for presenting the value variation of the progress bar.

In step 7, the texForefront stands for the forefront image of the progress bar; the texBackground represents the background image of the progress bar; position defines the progress bar position on the Windows Phone 7 screen; the last variable progressBar is the progress bar object which will perform the different progress behaviors.

In any type of game, button control is always the most basic and important part. In a GUI system, button control often plays a role in linking different parts of other controls. When you input some text in a text control, you click the button to send the message or confirm it as a command. When you are using a listbox, the up and down buttons help you look up special information that you need in the game, such as choosing weapons. In the development phase, programmers can define specific behaviors of the button events to implement the game logic or effects. To implement a button in the Windows Phone 7 XNA framework is not a hard mission. In this recipe, you will learn how to build your own button in Windows Phone 7.

How to do it…

The following steps will show you the working code for creating the buttons for your Windows Phone 7 game:

1. Create a Windows Phone Game project named Button, change Game1.cs to ButtonGame.cs. Then add the Button.cs to the main project and button_image.png and gameFont.spriteFont to the content project.
2. Create the Button class in the Button.cs file. Add the line to the class as a field:
[code]
// Button texture
Texture2D texButton;
// SpriteBatch for drawing the button image
SpriteBatch spriteBatch;
// Button position on the screen
public Vector2 Position;
// Color alpha value
public int Alpha = 255;
// Button color
Color color;
// Timer for game elapsed time accumulation
float timer;
// The Tapped bool value indicates whether tap in the button
region
public bool Tapped;
// Event handler OnTapped to react with tap gesture
public event EventHandler OnTapped;
[/code]
3. Then, define the HitRegion property of the Button class:
[code]
// Get the hit region
public Rectangle HitRegion
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y,
texButton.Width, texButton.Height);
}
}
[/code]
4. Next, give the class constructor Button() of the Button class:
[code]
// Initialize the button without text
public Button(Texture2D texture, Vector2 position, SpriteBatch
spriteBatch)
{
this.texButton = texture;
this.Position = position;
this.spriteBatch = spriteBatch;
color = Color.White;
}
[/code]
5. After the class constructor, the important Update() method that reacts to the tap gesture looks similar to the following code:
[code]
// Update the button
public void Update(GameTime gameTime, Vector2 touchPosition)
{
// React to the tap gesture
Point point = new Point((int)touchPosition.X,
(int)touchPosition.Y);
// If tapped button, set the Hovered to true and trigger
// the OnClick event
if (HitRegion.Contains(point))
{
Tapped = true;
OnTapped(this, null);
}
else
{
Tapped = false;
}
}
[/code]
6. The final step to build the Button class is to define the Draw() method:
[code]
// Draw the button
public virtual void Draw(GameTime gameTime)
{
timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
// Draw the button texture
if (Tapped)
{
// Flash the button through the alpha value changing
if (timer > 100)
{
// If the Alpha is 255, set it to 0
if (Alpha == 255)
{
Alpha = 0;
}
// If the Alpha value is 0, set it to 255
else if (Alpha == 0)
{
Alpha= 255;
}
// Set the color alpha value
color.A = (byte)Alpha;
// Set the timer to 0 for next frame
timer = 0;
}
// Draw the button image
spriteBatch.Draw(texButton, HitRegion, null, color, 0,
Vector2.Zero, SpriteEffects.None, 0);
}
else
{
spriteBatch.Draw(texButton, HitRegion,
null,Color.White, 0,
Vector2.Zero, SpriteEffects.None, 0);
}
}
[/code]
7. Use the Button class in our main game class. Insert code to the ButtonGame class field:
[code]
// Sprite Font for showing the text
SpriteFont font;
// Text object
string textTapState = “Random Color Text”;
// Text color;
Color textColor = Color.White;
// Random object for showing the random color
Random random;
// Button object
Button button;
// Button texture;
Texture2D buttonTexture;
[/code]
8. Initialize the random variable in the Initialize() method, and add the following code to the method:
[code]
random = new Random();
[/code]
9. Load the button image and initialize the button object. Add the code to the LoadContent() method:
[code]
Vector2 position = new Vector2(
GraphicsDevice.Viewport.Width / 2 – buttonTexture.Width / 2,
GraphicsDevice.Viewport.Height/2 – buttonTexture.Height / 2);
button = new Button(buttonTexture, position, spriteBatch);
button.OnTapped += new EventHandler(button_OnTapped);
[/code]
10. Next is the reaction method for the button OnTapped event:
[code]
void button_OnTapped(object sender, EventArgs e)
{
textColor.R = (byte)random.Next(0, 256);
textColor.G = (byte)random.Next(0, 256);
textColor.B = (byte)random.Next(0, 256);
}
[/code]
11. Get the tapped position and pass it to the Button.Update() method, paste the code in to the Update() method:
[code]
TouchCollection touches = TouchPanel.GetState();
if(touches.Count > 0 && touches[0].State ==
TouchLocationState.Pressed)
{
Vector2 tappostion = touches[0].Position;
button.Update(gameTime, tappostion);
}
[/code]
12. Draw the button on screen, and put the following lines of code to the Draw() method:
[code]
spriteBatch.Begin(SpriteSortMode.Immediate,
BlendState.NonPremultiplied);
button.Draw(gameTime);
spriteBatch.DrawString(font, textTapState, new Vector2(0, 0),
textColor);
spriteBatch.End();
[/code]
13. Ok, we have done the code work. Build and run the project, and the application should run similar to the following screenshot; when we tap the button, it will flicker and generate a random color for the text on the top-left corner.

How it works…

Steps 2–6 are about creating the Button class.

In step 2, the texButton is the button texture; spriteBatch will render the button texture on screen; Position specifies the location of the button on screen. Alpha represents the alpha value of the button color; timer will be used to accumulate the game elapsed time; bool value tapped will indicate the tapping state of the button; OnTap is the event handler to handle the button tap gesture.

In step 3, the HitRegion property will return the bound surrounding the button for tap validation.

In step 4, the constructor initializes the button texture, position, and color.

In step 5, within the Update() method of the Button class, the code checks the tapped position to see whether it’s inside the button HitRegion. If yes, set Tapped to true and trigger the OnTapped event, else, it will be false.

In step 6, the first line is to accumulate the game elapsed time in milliseconds. The following code draws the button image. If the button is tapped and the elapsed time is greater than 100, it will flicker. The effect is implemented by setting the Alpha value of button color. If the Alpha value equals 255 (Opaque), we set it to 0 (Transparent). Otherwise, the value will be set from 0 to 255. After that, the latest alpha value will be assigned to Color.A , the alpha factor of Color. Then, reset the timer for the next frame. The last line will render the flickering effect on screen.

Steps 7–11 are about using the Button class in the main game class.

In step 7, the font object will render the text on screen; the textTapState stores the text to be displayed; textColor specifies the text color; random will be used to generate a random color for the text; the button variable represents the Button class instance; the buttonTexture loads the button image.

In step 9, the button_OnTapped() method will run if the OnTapped event happens. In the event reaction method, we set the R, G, and B factors of text color randomly, because the RGB value is from 0 to 255, so the random value for each of them must be inside the range.

In step 10, we get the tapped position for the button hit region validation.

In step 11, notice we must set the BlendState.NonPremultiplied because we change the button image Alpha value linearly.

Creating a listbox to speed up your information management in a game

Listbox is a list-style control, which collects the information in the list. For games, list control often plays a role in information management. The items in the listbox are presented one-by-one vertically or horizontally. You can choose the information entry through the control. In this recipe, you will master the technique of building your own listbox.

The example will create a listbox in Windows Phone 7. When you click the scrollbar down or the down button, the listbox will show the list items from the latest index. Once you tap one of the items, the text of the item will be presented at the top-left of the screen. Now, let’s begin with building the Button class.

How to do it…

The following steps will show you the complete process of creating the GUI listbox control:

1. Create the Windows Phone Game project named ListBoxControl, change Game1.cs to ListBoxControlGame.cs. Add the Button.cs, ScrollBar. cs, and ListBox.cs files to the main project, and add gameFont.spriteFont, ListBoxBackground.png, ScrollBarDown.png, and ScrollBarUp.png to the content project.
2. Create the Button class in Button.cs. First, insert the lines as the field of the Button class:
[code]
// Button texture
Texture2D texButton;
// SpriteBatch for drawing the button image
SpriteBatch spriteBatch;
// Button position on the screen
public Vector2 Position;
// Button color
Color color;
// The Tapped bool value indicates whether tap in the button
region
public bool Tapped;
// Event handler OnTap to react with tap gesture
public event EventHandler OnTapped;
[/code]
3. The next part is the HitRegion property:
[code]
// Get the hit region
public Rectangle HitRegion
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y,
texButton.Width, texButton.Height);
}
}
[/code]
4. After the property definition, the constructor will be:
[code]
// Initialize the button without text
public Button(Texture2D texture, Vector2 position, SpriteBatch
spriteBatch)
{
this.texButton = texture;
this.Position = position;
this.spriteBatch = spriteBatch;
color = Color.White;
}
[/code]
5. Then, we define the Update() method:
[code]
// Update the button
public void Update(GameTime gameTime, Vector2 touchPosition)
{
// React to the tap gesture
Point point = new Point((int)touchPosition.X,
(int)touchPosition.Y);
// If tapped button, set the Hovered to true and trigger
// the OnClick event
if (HitRegion.Contains(point))
{
Tapped = true;
OnTapped(this, null);
}
else
{
Tapped = false;
}
}
[/code]
6. The final method in the Button class is the Draw() method:
[code]
// Draw the button
public virtual void Draw(GameTime gameTime)
{
// Draw the button texture
if (Tapped)
{
spriteBatch.Draw(texButton, HitRegion, null,
Color.Red, 0,
Vector2.Zero, SpriteEffects.None, 0);
}
else
{
spriteBatch.Draw(texButton, HitRegion,
null,Color.White, 0,
Vector2.Zero, SpriteEffects.None, 0);
}
}
[/code]
7. Create the ScrollBar class in ScrollBar.cs. As the class field, we use the following code:
[code]
// SpriteBatch for drawing the scrollbar
SpriteBatch spriteBatch;
// ScrollBar up and down buttons
Button scrollUp;
Button scrollDown;
// Textures for scrollbar up and down buttons
Texture2D texScrollUp;
Texture2D texScrollDown;
// The position of scrollbar
public Vector2 Position;
// The positions of scrollbar up and down buttons
public Vector2 scrollUpPosition;
public Vector2 scrollDownPosition;
// Event handler when scrollbar up button tapped
public event EventHandler OnScrollUpTapped;
// Event handler when scrollbar down button tapped
public event EventHandler OnScrollDownTapped;
// The ScrollBar Height and Width
public int ScrollBarHeight;
public int ScrollBarWidth;
[/code]
8. The following code is the ScrollDownBound and ScrollUpBound property of the ScrollBar class:
[code]
// The Bound of Scrollbar down button
public Rectangle ScrollDownBound
{
get
{
return new Rectangle((int)scrollDownPosition.X,
(int)scrollDownPosition.Y,
(int)texScrollDown.Width,
(int)texScrollDown.Height);
}
}
// The Bound of Scrollbar up button
public Rectangle ScrollUpBound
{
get
{
return new Rectangle((int)scrollUpPosition.X,
(int)scrollUpPosition.Y,
(int)texScrollDown.Width,
(int)texScrollDown.Height);
}
}
[/code]
9. After the properties, the constructor of the ScrollBar class should be as follows:
[code]
// ScrollBar constructor
public ScrollBar(Vector2 position, int scrollbarHeight,
ContentManager content, SpriteBatch spriteBatch)
{
// Load the textures of scroll bar up and down button
Position = position;
this.spriteBatch = spriteBatch;
// Get the scrollbar width and height
this.ScrollBarWidth = texScrollDown.Width;
this.ScrollBarHeight = scrollbarHeight;
// The position of scrollbar up button
this.scrollUpPosition = new Vector2(
Position.X – ScrollBarWidth / 2, Position.Y);
// The position of scrollbar down button
this.scrollDownPosition = new Vector2(
Position.X – ScrollBarWidth / 2,
Position.Y + ScrollBarHeight – texScrollDown.Height);
// Instance the scrollbar up and down buttons
scrollUp = new Button(texScrollUp, scrollUpPosition,
spriteBatch);
scrollDown = new Button(texScrollDown, scrollDownPosition,
spriteBatch);
}
[/code]
10. Next, we define the Update() method of the Scrollbar class:
[code]
// Scrollbar Update method
public void Update(GameTime gameTime, Vector2 tappedPosition)
{
// Check whether the tapped position is in the bound of
// scrollbar up button
if (ScrollDownBound.Contains((int)tappedPosition.X,
(int)tappedPosition.Y))
{
// If yes, set the Tapped property of scrollbar down
// button to true
scrollDown.Tapped = true;
// Set the Tapped property of scrollbar up button to
// false
scrollUp.Tapped = false;
// Trigger the scrollbar down button event
OnScrollDownTapped(this, null);
}
else if(ScrollUpBound.Contains((int)tappedPosition.X,
(int)tappedPosition.Y))
{
// If yes, set the Tapped property of scrollbar up
// button to true
scrollUp.Tapped = true;
// Set the Tapped property of scrollbar down button to
// false
scrollDown.Tapped = false;
// Trigger the scrollbar up button event
OnScrollUpTapped(this, null);
}
}
[/code]
11. Then, draw the scrollbar on screen by using the Draw() method:
[code]
// Draw the scrollbar
public void Draw(GameTime gameTime)
{
// Draw the scrollbar down and up buttons
scrollDown.Draw(gameTime);
scrollUp.Draw(gameTime);
}
[/code]
12. Create the ListBox class in the ListBox.cs file. We add the following code as the class field:
[code]
// Game object holds the listbox
Game game;
// SpriteBatch for drawing listbox
SpriteBatch spriteBatch;
// SpriteFont object for showing the listbox text items
SpriteFont font;
// The listbox background texture
Texture2D texBackground;
// The collection of listbox text items
public List<string> list;
// The position of listbox on screen
public Vector2 Position;
// The count of the listbox text items
public int Count;
// Scrollbar object to control the text items for showing
ScrollBar scrollBar;
// The Index for locating the specified item in listbox
public int Index = 0;
// The bounds of showed items
List<Rectangle> listItemBounds;
// The index of selected items
public int SelectedIndex = 0;
// The selected item
public string SelectedItem = “”;
// The selected area for highlighting the selected item
Texture2D SelectedArea;
// The offset from the position of listbox as the beginning of
// drawing the text items
Vector2 Offset;
// The width and height of listbox
int ListBoxWidth;
int ListBoxHeight;
// The total number of items presenting in listbox
int ShowedItemCount = 0;
[/code]
13. As properties, the CharacterHeight and Bound look similar to the following:
[code]
// Get the character height o text item
public float CharacterHeight
{
get
{
if (font != null && list.Count > 0)
{
// The Y value represents the character height in
// the returned Vector2 value
// of SpriteFont.MeasureString()
return font.MeasureString(list[0]).Y;
}
else
{
throw new Exception();
}
}
}
// Get the bound of listbox
public Rectangle Bound
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y,
texBackground.Width, texBackground.Height);
}
}
[/code]
14. The next block of code is the constructor of the ListBox class:
[code]
// Listbox constructor
public ListBox(Vector2 position, ContentManager content,
SpriteBatch
spriteBatch, Game game)
{
this.game = game;
this.spriteBatch = spriteBatch;
listItemBounds = new List<Rectangle>();
list = new List<string>();
Position = position;
texBackground =
ListBoxWidth = texBackground.Width;
ListBoxHeight = texBackground.Height;
// Define the scrollbar position relative to the position
// of listbox
Vector2 scrollBarPosition = new Vector2(
Position.X + ListBoxWidth + 40, Position.Y);
// Instance the scrollbar
scrollBar = new ScrollBar(scrollBarPosition, ListBoxHeight,
content, spriteBatch);
scrollBar.OnScrollUpTapped += new
EventHandler(scrollBar_OnScrollUpTapped);
scrollBar.OnScrollDownTapped += new
EventHandler(scrollBar_OnScrollDownTapped);
// Define the offset for drawing the text items
Offset = new Vector2(20, 4);
}
[/code]
15. Now, we define the reaction method of the tap event of the scrollbar’s up and down buttons:
[code]
// The reaction method of scrollbar down button tapping event
void scrollBar_OnScrollDownTapped(object sender, EventArgs e)
{
// If the current item index plus the ShowedItemCount
// is less
// than count of list items, increase the Index
if (Index + ShowedItemCount < Count)
{
Index++;
}
}
// The reaction method of scrollbar up button tapping event
void scrollBar_OnScrollUpTapped(object sender, EventArgs e)
{
// If the current item index is greater than 0, decrease
the
// Index
if (Index > 0)
{
Index–;
}
}
[/code]
16. The following important method in the ListBox class is the Update() method:
[code]
// Check the tapping state of scrollbar and the selection of
// listbox items
public void Update(GameTime gameTime, Vector2 tapposition)
{
scrollBar.Update(gameTime, tapposition);
CheckSelected(tapposition);
}
[/code]
17. The definition of CheckSelected() is as follows:
[code]
// Get the selected index and item in listbox
private void CheckSelected(Vector2 tappedPosition)
{
for (int i = 0; i < ShowedItemCount; i++)
{
// Check whether the tapped position is in the region
of
// listbox and in which one of the item bounds.
if (Bound.Contains(
(int)tappedPosition.X, (int)tappedPosition.Y)
&& tappedPosition.Y <
listItemBounds[i].Y + CharacterHeight)
{
SelectedIndex = i;
SelectedItem = list[Index + i];
break;
}
}
}
[/code]
18. Before giving the definitions of the AddItem() and RemoveItem() methods, let’s give the definition of the GetListItemBound() method:
[code]
private void GetListItemBound(List<String> list)
{
// If the count of the items is greater than 0
if (list.Count > 0)
{
Rectangle itemBound;
// If the current count of item is less than the
// ShowedItemCount, set the LoopBound to Count, else,
// set it to ShowedItemCount.
int LoopBound = Count < ShowedItemCount ? Count :
ShowedItemCount;
// Get the item bounds
for (int i = 0; i < LoopBound; i++)
{
itemBound = new Rectangle(
(int)Position.X,
(int)(Position.Y + Offset.Y) +
font.LineSpacing * i,
(int)ListBoxWidth, (int)CharacterHeight);
}
}
}
[/code]
19. Next it’s time for implementing the AddItem() and the RemoveItem() methods:
[code]
// Add text item to listbox
{
// Add the text item to the list object
// Update total number of list items
Count = list.Count;
// Set the limited count for showing the list items
if (list.Count == 1)
{
ShowedItemCount = (int)(texBackground.Height /
CharacterHeight);
}
// Get the text item bounds
listItemBounds.Clear();
GetListItemBound(list);
}
[/code]
20. Now, define the RemoveItem() method:
[code]
public void RemoveItem(string str)
{
// Delete the text item from the list items
this.list.Remove(str);
// Update the total number of list items
Count = list.Count;
GetListItemBound(list);
}
[/code]
21. After the text item management functions, is the Selection Area creating method:
[code]
// Create the texture of the selected area
private void CreateSelectedArea(Rectangle rectangle)
{
// Initialize the selected area texture
SelectedArea = new Texture2D(game.GraphicsDevice,
rectangle.Width, rectangle.Height, false,
SurfaceFormat.Color);
// Initialize the pixels for the texture
Color[] pixels = new Color[SelectedArea.Width *
SelectedArea.Height];
for (int y = 0; y < SelectedArea.Height; y++)
{
for (int x = 0; x < SelectedArea.Width; x++)
{
pixels[x + y * SelectedArea.Width] =
new Color(new Vector4(125f, 125f,125f, 0.5f));
}
}
// Set the pixels to the selected area texture
SelectedArea.SetData<Color>(pixels);
}
[/code]
22. The final step in building the ListBox class is to draw the listbox on screen through the Draw() method:
[code]
public void Draw(GameTime gameTime)
{
// Draw the listbox background
spriteBatch.Draw(texBackground, Position, Color.White);
// The text items exist
if (Count > 0)
{
// If current count of items is less than the
// ShowedItemCount, show the items one by one
// from the beginning
if (Count <= ShowedItemCount)
{
for (int i = 0; i < Count; i++)
{
spriteBatch.DrawString(font, list[i],
Position + new Vector2(
Offset.X, Offset.Y + font.LineSpacing * i),
Color.White);
}
}
// If current count of items is greater than the
// ShowedItemCount, show the items from the current
// index.
else
{
for (int i = 0; i < ShowedItemCount; i++)
{
spriteBatch.DrawString(font, list[i + Index],
Position + new Vector2(
Offset.X, Offset.Y + font.LineSpacing * i),
Color.White);
}
}
// If the SelectionArea is not created, creat a new
// one
if (SelectedArea == null)
{
CreateSelectedArea(listItemBounds[0]);
}
// Draw the SelectedArea texture
spriteBatch.Draw(SelectedArea,
listItemBounds[SelectedIndex], Color.White);
}
scrollBar.Draw(gameTime);
}
[/code]
23. Woo! The ListBox class and its dependent classes are done. Now, we will use the ListBox class in our main project, and this is simple and easy to code. Insert the following lines to the ListBoxControlGame class field:
[code]
SpriteFont spriteFont;
ListBox listBox;
[/code]
24. Initialize the spriteFont object and listBox. Add the lines in the LoadContent() method:
[code]
// Create a new SpriteBatch, which can be used to draw
textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
listBox = new ListBox(new Vector2(200, 100), this.Content,
spriteBatch, this);
[/code]
25. Get the tapped position on listBox. Paste the following code to the Update() method:
[code]
TouchCollection touches = TouchPanel.GetState();
if (touches.Count > 0 && touches[0].State ==
TouchLocationState.Pressed)
{
Vector2 tapposition = touches[0].Position;
listBox.Update(gameTime, tapposition);
}
[/code]
26. Draw the listbox and selected text item on screen, and insert the block of code in to the Draw() method:
[code]
spriteBatch.Begin(SpriteSortMode.Immediate,
BlendState.NonPremultiplied);
listBox.Draw(gameTime);
spriteBatch.DrawString(spriteFont,
“ SelectedItem: “ + listBox.SelectedItem,
new Vector2(0, 0), Color.White);
spriteBatch.End();
[/code]
27. The whole project is complete. Build and run the application. It should look similar to the following screenshots:

How it works…

Steps 1–6 are about creating the Button class.

In step 2, the texButton stores the button texture; spriteBatch will render the button texture on screen; Position defines the button position on screen; the color object represents the button color; Tapped shows the tapping state of the button; OnTap is the event handler of tap gesture.

In step 3, the HitRegion property returns the button hit region around the button background texture.

In step 5, the Update() method gets the tapped position and checks whether it’s inside the button hit region. If yes, set Tapped to true and trigger the OnTapped event. Else, set Tapped to false.

In step 6, the code draws a button on the Windows Phone 7 screen. If the button is tapped, draw the button in red, or else, in white.

Steps 7–11 are about implementing the Scrollbar class.

In step 7, the spriteBatch will render the scrollbar background texture on screen; the scrollUp and scrollDown buttons will be used to increase or decrease the index of listbox items; Position stores the position of the scrollbar; scrollUpPosition and scrollDownPosition maintain the positions of the scrollUp and scrollDown buttons; the following two event handlers specify the tap events of the two scroll buttons when they are tapped. The two variables ScrollBarHeight and ScrollBarWidth define the height and width of the scrollbar buttons.

In step 8, the ScrollDownBound property returns the bound around the scrollDown button, similar to the ScrollUpBound property.

In step 9, the constructor initializes the two scrollbar buttons and gets the scrollbar width and height.

In step 10, the Update() method checks the tapped position to see whether it’s in the ScrollDownBound, if yes, set the Tapped of scrollDown to true and the property of scrollUp to false, then trigger the OnScrollDownTapped event; otherwise, do similar things for ScrollUpBound.

Steps 12–22 are to build the ListBox class using Button and Scrollbar classes.

In step 12, the game is the object of Game that supplies the GraphicDevice for drawing the selection area texture; spriteBatch will draw the listbox on screen; font will be used to draw the text of the listbox items; texBackground holds the listbox background texture; list is the collection of listbox text items; Position specifies the position of the listbox; Count shows the current total number of listbox items; scrollbar is the object of ScrollBar used to explore the listbox items; Index shows the current beginning index in listbox items; listItemBounds is the collection the bounds of list items. The following two variables indicate the index of the selected item in the listbox; if the item is selected, the SelectedArea will present a rectangle texture around the item; Offset is the position for drawing the text item relative to the position of the listbox; ShowedItemCount saves the maximum limitation of the number for rendering listbox items.

In step 13, the CharacterHeight returns the character height of the listbox text item. The Bound property gets the rectangle surrounding the listbox.

In step 15, when the scrollUp button is tapped, the Index will increase by 1 if the sum of Index plus ShowedItemCount is less than the amount of listbox items. While the scrollDown button is tapped and the Index is greater than 0, we will decrease the Index by one.

In step 16, first the Update() method checks the tapped position, to see whether it’s inside the buttons of the scrollbar. Then, use the CheckSelected() method to check the listbox item selection.

In step 17, because the ShowedItemCount limits the number for showing items, we just need to do the same steps for the loop. In the body of the for loop, first we check the tapped position to see whether it’s in the bound of the listbox, then we examine the lower-side of the current item bound to see whether it is greater than the Y factor of the tapped position. If so, it means the tapped position is in the region of the current item bound that is selected. Now, we set the current i to the SelectedIndex and the content of the current item to SelectedItem. The break here is important, as we only need the first selected one.

In step 18, we implement the GetListItemBound() method. When the list.Count is greater than 0 and if the current count of listbox item is less than ShowedItemCount, the loop will be equal to the Count; otherwise, the ShowedCount should be the LoopBound. In the loop, the code generates the item bound with the CharacterHeight and ListBoxWidth.

In step 19, once every new listbox item is added to the list, we will update the Count. This stands for the total number of listbox items. We get the ShowedItemCount when there is an item in the listbox. After that, we obtain the bounds of items through the GetListItemBound() method defined in step 18.

In step 21, the CreateSelectedArea() method first creates a new texture— SelectedArea which has the same size as the method parameter—rectangle. The second line defines the dimension of pixels equal to the SelectedArea. In the for loop, we set the actual color to each pixel of the new texture. Finally, the SetData() method copies the pixels to the SelectedArea for texture drawing.

In step 22, the first line of the Draw() method draws the listbox background texture. When the Count is greater than 0 and is equal to, or less than, the ShowedItemCount, the list item will be drawn one by one from the beginning of the list. Otherwise, we draw the items from the current index. After that, if one of the list items is selected, the SelectionArea will also be rendered around the selected item.

Steps 23–26 are for drawing the listbox on screen in the main game class ListBoxControlGame.

Creating a text input control to communicate with others in a game

Textbox is a very common and useful control in applications, reading the input and displaying the symbols in the main area. For multiplayer games, players love to use the control to communicate with each other for exchanging their thoughts. A textbox control can also act like a command line for controlling the game settings. With textbox control and corresponding functions, you can do a lot of things. In this recipe, you will learn how to make your own textbox control in Windows Phone 7.

How to do it…

The following steps will help you to implement a text input control for communicating in your own Windows Phone 7 game:

1. Create a Windows Phone Game project in Visual Studio 2010 named TextBox, and change Game1.cs to TextBoxGame.cs. Then, add cursor.png, button.png, backspace.png, TextboxBackground.png, and gameFont.spriteFont to the content project.
2. Now, let’s develop a button class for input. First of all, in the Button.cs file we declare the class field and property:
[code]
// Button texture
Texture2D texButton;
// SpriteBatch for drawing the button image
SpriteBatch spriteBatch;
// SpriteFont for drawing the button text
SpriteFont font;
// Button text
public String Text = “”;
// Button text position on the screen
public Vector2 TextPosition;
// Button text size
public Vector2 TextSize;
// Button position on the screen
public Vector2 Position;
// The Clicked bool value indicates whether tap in the button
public bool Clicked;
// Event handler when tap on the button
public event EventHandler OnClicked;
// Get the hit region
public Rectangle HitRegion
{
get
{
return new Rectangle((int)Position.X, (int)Position.Y,
texButton.Width, texButton.Height);
}
}
[/code]
3. Next, we define two overload constructors of the Button class:
[code]
// Initialize the button without text
public Button(Texture2D texture, Vector2 position, SpriteFont
font, SpriteBatch spriteBatch)
{
this.texButton = texture;
this.Position = position;
this.spriteBatch = spriteBatch;
this.font = font;
}
// Initialize the button with text
public Button(Texture2D texture, Vector2 position, String
text, SpriteFont font, SpriteBatch spriteBatch)
{
this.texButton = texture;
this.Position = position;
this.spriteBatch = spriteBatch;
this.Text = text;
// Compute the text size and place the text in the center
// of the button
TextSize = font.MeasureString(Text);
this.TextPosition = new Vector2(position.X +
texture.Width / 2 – TextSize.X / 2, position.Y);
this.font = font;
}
[/code]
4. In the following step, we will make the button react to the tap gesture. Add the Update() code as follows:
[code]
// Update the button
public void Update(GameTime gameTime, Vector2 touchPosition)
{
// React to the tap gesture
Point point = new Point((int)touchPosition.X,
(int)touchPosition.Y);
// If tapped button, set the Hovered to true and trigger
// the OnClick event
if (HitRegion.Contains(point))
{
Clicked = true;
OnClicked(this, null);
}
// Update the button
public void Update(GameTime gameTime, Vector2 touchPosition)
{
// React to the tap gesture
Point point = new Point((int)touchPosition.X,
(int)touchPosition.Y);
// If tapped button, set the Hovered to true and trigger
// the OnClick event
if (HitRegion.Contains(point))
{
Clicked = true;
OnClicked(this, null);
}
[/code]
5. The final step for the Button class is to draw it on the screen. To do this, we use this block of code:
[code]
// Draw the button
public virtual void Draw()
{
// Draw the button texture
if (!Clicked)
{
spriteBatch.Draw(texButton, HitRegion, Color.White);
}
else
{
spriteBatch.Draw(texButton, HitRegion, Color.Red);
}
// Draw the button text
spriteBatch.DrawString(font, Text, TextPosition,
Color.White);
}
[/code]
6. In this step, we begin to write the TextBoxControl class. In TextBoxControl.cs, add the lines to the TextBoxControl class as fields:
[code]
// SpriteBatch for drawing the textbox texture
SpriteBatch spriteBatch;
// SpriteFont for drawing the textbox font
SpriteFont spriteFont;
// Textbox background texture
Texture2D texBackGround;
// Textbox cursor texture
Texture2D texCursor;
// Textbox Bound for showing the text
public Rectangle Bound;
// Textbox position
public Vector2 Position;
// Textbox cursor position
public Vector2 CursorPosition;
// Timer used to control the cursor alpha value
float timer;
// Text position in the textbox
public Vector2 TextPosition;
// The text size of the showing text
public Vector2 textSize;
// The character size of the textbox text
private float characterSize;
// Alpha value for the cursor
int alpha = 255;
// The cursor color
Color cursorColor;
// TypedText stores the typed letters
public string TypedText = “”;
// ShowedText saves the text shown in the textbox
public string ShowedText = “”;
[/code]
7. Next, we add the properties to the TextBoxControl class:
[code]
// Get the character size
public float CharacterSize
{
get
{
textSize = spriteFont.MeasureString(TypedText);
characterSize = textSize.X / TypedText.Length;
return characterSize;
}
}
// Get the text size
public Vector2 TextSize
{
get
{
return textSize = spriteFont.MeasureString(TypedText);
}
}
// Get the bound for showing the text
public int ShowedCharacterBound
{
get
{
return (int)(Bound.Width / CharacterSize);
}
}
[/code]
8. The following part is about the TextBoxControl class initialization, and the constructer looks as follows:
[code]
// Initialize the textbox
public TextBoxControl(Vector2 position, Texture2D texCursor,
Texture2D texBackground, SpriteFont font, SpriteBatch
spriteBatch)
{
this.Position = position;
this.spriteBatch = spriteBatch;
this.texCursor = texCursor;
this.spriteFont = font;
this.texBackGround = texBackground;
// Set the bound of textbox control
Bound = new Rectangle((int)position.X, (int)position.Y,
texBackGround.Width, texBackGround.Height);
// Set the cursor position
this.CursorPosition = new Vector2(position.X + 10,
position.Y + 10);
// Set the text position
this.TextPosition = new Vector2(position.X + 10,
position.Y);
// Set the cursor color with alpha value
cursorColor = new Color(255, 255, 255, alpha);
}
[/code]
9. After the initialization, the following code is the definition of the Update() method:
[code]
public void Update(GameTime time)
{
// Accumulate the game elapsed milliseconds
timer += (float)time.ElapsedGameTime.TotalMilliseconds;
// Every 500 milliseconds the alpha value of the cursor
will
// change from 255 to 0 or 0 to 255.
if (timer > 500)
{
if (alpha == 255)
{
alpha = 0;
}
else if (alpha == 0)
{
alpha = 255;
}
cursorColor.A = (byte)alpha;
timer = 0;
}
}
[/code]
10. Then we define the Draw() method :
[code]
public void Draw()
{
// Draw the textbox control background
spriteBatch.Draw(texBackGround, Position, Color.White);
// Draw the textbox control cursor
spriteBatch.Draw(texCursor, CursorPosition, cursorColor);
// Draw the textbox showing text
spriteBatch.DrawString(spriteFont, ShowedText,
TextPosition, Color.White);
}
[/code]
11. From this step, we will use the Button class and the TextBoxControl class in the main game class. Now, add the lines to the TextBoxGame class fields:
[code]
// SpriteFont object
SpriteFont font;
// TextboxControl object
TextBoxControl textBox;
// Button objects
Button buttonA;
Button buttonB;
Button buttonBackspace;
[/code]
12. Initialize the textbox control and buttons. Insert the code to the LoadContent() method:
[code]
Texture2D texTextboxBackground =
// Define the textbox position
Vector2 position = new Vector2(400, 240);
// Initialize the textbox
textBox = new TextBoxControl(position, texCursor,
texTextboxBackground, font, spriteBatch);
// Initialize the buttonA
buttonA = new Button(texButton, new Vector2(400, 350), “A”,
font, spriteBatch);
buttonA.OnClicked += new EventHandler(button_OnClicked);
// Initialize the buttonB
buttonB = new Button(texButton, new Vector2(460, 350), “B”,
font, spriteBatch);
buttonB.OnClicked += new EventHandler(button_OnClicked);
// Initialize the backspace button
buttonBackspace = new Button(texBackSpace,
new Vector2(520, 350), font, spriteBatch);
buttonBackspace.OnClicked += new
EventHandler(buttonBackspace_OnClicked);
[/code]
13. Define the event handling code for buttonA and button, which is same for both:
[code]
void button_OnClicked(object sender, EventArgs e)
{
// Add the button text to the textbox TypedText
// Update the position of textbox cursor
textBox.CursorPosition.X = textBox.TextPosition.X +
textBox.TypedText += ((Button)sender).Text;
textBox.TextSize.X;
// Get the textbox showed character bound
int showedCharacterBound = textBox.ShowedCharacterBound;
// check whether the textbox cursor goes outside of the
// textbox bound
if (textBox.CursorPosition.X > textBox.Bound.X +
textBox.Bound.Width)
{
// If yes, set cursor positon at the right side of
// the textbox
textBox.CursorPosition.X = textBox.TextPosition.X +
textBox.CharacterSize * showedCharacterBound;
// Show the TypedText from end to the left in
// the range for showing characters of textbox
textBox.ShowedText =
textBox.TypedText.Substring(textBox.TypedText.Length –
showedCharacterBound – 1, showedCharacterBound);
}
else
{
// If not, just set the current TypedText to the
// showedText
textBox.ShowedText = textBox.TypedText;
}
}
[/code]
14. The next block of code is the handling code for the backspace button:
[code]
void buttonBackspace_OnClicked(object sender, EventArgs e)
{
// Get the length of TypedText
int textLength = textBox.TypedText.Length;
// Check whether the TypedText is greater than 0
if (textLength > 0)
{
// If yes, delete the last character
textBox.TypedText = textBox.TypedText.Substring(0,
textLength – 1) ;
// Get the current showed character count.
int showedCharacterCount = (int)(textBox.TextSize.X /
textBox.CharacterSize);
// Check whether the current showed character count is
less than
// the textbox showed character bound
if (showedCharacterCount <=
textBox.ShowedCharacterBound)
{
// If yes, just update the cursor position with
// current text size and the showedText with
// current text
textBox.CursorPosition.X = textBox.TextPosition.X
+ textBox.TextSize.X;
textBox.ShowedText = textBox.TypedText;
}
else
{
// If not, show the TypedText from end to the
// left in the range for showing characters
// of textbox
textBox.ShowedText = textBox.TypedText.Substring(
textBox.TypedText.Length –
textBox.ShowedCharacterBound,
textBox.ShowedCharacterBound);
}
}
}
[/code]
15. Trigger the button event. Add the code to the Update() method:
[code]
TouchCollection touches = TouchPanel.GetState();
if(touches.Count > 0 && touches[0].State ==
TouchLocationState.Pressed)
{
buttonA.Update(gameTime, touches[0].Position);
buttonB.Update(gameTime, touches[0].Position);
buttonBackspace.Update(gameTime, touches[0].Position);
}
textBox.Update(gameTime);
[/code]
16. Draw the textbox and buttons on screen. Paste the code into the Draw() method:
[code]
spriteBatch.Begin();
textBox.Draw();
buttonA.Draw();
buttonB.Draw();
buttonBackspace.Draw();
spriteBatch.End();
[/code]
17. Now, build and run the application. When you tap button A and button B, the textbox will show the input as shown in the following screenshot to the left. When you tap the backspace button, it will look similar to the following screenshot on the right:

How it works…

Steps 2–5 are responsible for creating the Button class:

In step 2, the texButton stores the button texture; font will be used to render the button text, we use the button Text for the input text; the position variable tells you where the button is on the screen; the bool value Clicked indicates whether the tap gesture takes place in the button hit region; when the button is clicked, the OnClicked event will be triggered. The HitRegion property returns the bound of the button for clicking.

In step 3, the first constructor initializes the button without text. The second constructor initializes the button with text and places the text in the center of the button. The SpriteFont.MeasureString() method computes and returns the text size as a Vector2, the X value holds the text width, and the Y value holds the text height.

In step 4, the reacting code first gets the tapped position, then use the Rectangel. Contains() method to check whether the position is inside the hit region, if yes, we set the Clicked to true and trigger the OnClicked() event.

Steps 6–10 are about creating the TextBoxControl class:

In step 6, the first four variables deal with the textbox texture and font; the following Bound variable stores the textbox bound for showing text; Position indicates the location of the textbox control on the screen; the CursorPosition represents the cursor place within the textbox control bound; the timer variable will be used to control the alpha value of the cursor for the flashing effect; the TextPosition shows the text position inside the textbox control; textSize represents the size of the TypedText; the characterSize defines the size of a single character of the TypedText; the ShowedText stores the text that will be presented in the textbox.

In step 7, the CharacterSize returns the size of a single character in the TypedText, we use SpriteFont.MeasureString() to compute the size of the TypedText, then use the X value of the textSize and divide the TypedText length to get the unit character length; the TextSize returns the size of TypedText; ShowedCharacterBound returns the region for showing the TypedText.

In step 9, the Update() method checks whether the accumulated milliseconds are greater than 500 or not. If yes and the alpha value is equal to 255 (opaque), it will be set to 0 (transparent), and vice versa. After setting the latest alpha value to alpha factor of cursor color—cursorColor.A, we reset the timer for the next interval.

Steps 11–16 are about using the Button and TextBoxControl class in the main class. We will draw the button and textbox control on the Windows Phone 7 screen and perform the reactions for text input and delete.

In step 11, the textBox stands for the TextBoxControl; buttonA represents the button for input character A; buttonB is used to input character B; the buttonBackspace will delete the character of the TypedText from the end to the beginning.

In step 12, the code loads the textures for the textbox and buttons first. Then, it initializes their event handling code.

In step 13, the code reacts to the event triggered from buttonA or buttonB. The first line casts the sender to Button. Then add the Text value to the TextBoxControl.TypedText. After getting the text, the cursor position is updated following the new TypedText. The rest of the code deals with the situation when the length of the TypedText is greater than the textbox bound. If this happens, the cursor will still stay at the right-side of the textbox, the showedText will be the substring of the TypedText from the end to the left in the range for showing characters of the textbox. On the other hand, the entire TypedText will be drawn.

In step 14, as the reaction code for the backspace button, at the beginning, we get the length of the TypedText. Then check whether it is greater than 0. If yes, we delete the last character. The rest of the code works with the state when the deleted TypedText length is greater or less than the textbox bound. If greater, the showedText will range from the end of the deleted TypedText to the left about the showed character count of the textbox. Otherwise, the cursor will follow the current TypedText, which will be completely rendered on the screen.

## Using the IronPython Windowed Environment

IronPython also provides access to a windowed environment, but you can’t access it from the start menu. Instead, you  must provide a shortcut to the file you want to run or open a command prompt and start the application manually. The windowed environment simply provides a GUI interface for working with IronPython, but doesn’t do anything else for you. You start the windowed environment by using IPYW .EXE. If you type IPYW and press Enter, you see the command line switch help shown in Figure 1-9.

As you can see from Figure 1-9, the windowed environment supports the same command line switches as the character mode command line version. However, you can’t use the windowed environment to run the interpreted console environment, which is a shame because many developers would prefer working in the nicer environment. To see that the windowed environment works the same way as the standard console, type IPYW WFDemo.py and press Enter.

## Mobile Utility Applications

Several mobile utility applications are available for AIR developers.

As its name indicates, this Adobe Labs beta tool gives Flex developers a head start in creating AIR desktop and mobile applications. Launchpad is an AIR application that generates a complete Flex project that is ready to import to Flash Builder.

The process consists of four steps. The Settings option is for the application descriptor and permissions. The Configuration option is for setting up listeners of various events, such as the application moving to the background. The Samples option is for importing sample code for the APIs, such as Geolocation or Microphone. The Generate option creates a ZIP file at the location of your choice, ready to be imported. Sample icons and assets are automatically included based on your selection.

Device Central CS5

Adobe Device Central is not available for AIR development. At the time of this writing, it is targeted at Flash Player development only. It provides useful tools such as accelerometer simulation that can otherwise only be tested on the device. ADL provides some, albeit more limited, functionality. It can simulate soft keys and device rotation.

Package Assistant Pro

Serge Jespers, from Adobe, wrote an AIR application that facilitates the packaging of AIR applications for Android. You can download the Mac OS X and Windows versions from http://www.webkitchen.be/package-assistant-pro/. Note that you need the .swf file, the application descriptor file, and the code-signing certificate.

The packager preferences store the location of the AIR SDK adt.jar (located in AIRsdk/lib/) and your code-signing certificate. The packaging process consists of a few easy steps, all accomplished via a user interface. Browse to select the required files, enter your certificate password, and choose a name for the APK file. You can choose to compile a device release or a debug version.

This tool is convenient if you use one of the tools we will discuss next, and is a nice GUI alternative to using the command-line tool.

De MonsterDebugger

De MonsterDebugger is an open source debugger for Flash, Flex, and AIR. Version 3.0 provides the ability to debug applications running on your device and send the output straight to an AIR desktop application. It lets you manipulate values, execute methods, and browse the display list. For more information, go to http://demonsterdebugger.com/.