Another week, another article bringing us one step further in the creation of TriangleShooter. Last week, we did a bit of refactoring and broke Player and Enemy out into classes. At the time, this didn’t change anything in how the application worked, but this week, we’ll take advantage of it by adding in some basic AI, and then showing how easily you can scale out to more enemies. We’re going to be starting with the project we created worked on last week, so you can grab that from the SkyDrive Share.

The first thing we can do is make the enemy seem a bit more impressive. He was just sitting out there while we flew all around him just making fun of his inability to move. Well, let’s change that. We’ll begin by some basic animation. We’re not going into sprite frames or anything like that, a rotation should do. In the update method, we’ll add a line to update the enemy’s rotation. Let’s drop it in right before the collision detection. Rotation is handled as a float, in radians. That means that when the rotation is equal to 2*pi, it will be a single rotation. Since rotation is cyclical, and bounded between 0 and 2*pi, we can make use of the modulus operator to make sure that it doesn’t eventually exceed the boundary of what a float can handle.

Rotating the Enemy

enemy.Rotation += ((float)Math.PI / 30f) % ((float)Math.PI * 2);

We’ll need to update the Draw function as well, to make use of the newly updated rotation. We’ll use the same format as we did for the player. The main difference will be that the origin of rotation for the enemy will be the center.

If you run the application now, it works much like it did at the end of the last article, but now the enemy rotates. That simple change makes the visuals of the game quite a bit more interesting. It also gives us a great view into how easy it is going to be to add in some additional AI.

Let’s jump right into that. We’ve already seen how easy it is to make the player move towards a touch point. Let’s do the same thing with the enemy, and set the destination to the player. That’s the basis for follow AI. Add the following lines to the Update method right after the line that updates the rotation.

Follow AI

Vector2 enemyDirection = player.Position - enemy.Position;

if (enemyDirection.LengthSquared() > enemy.Speed * enemy.Speed)

{

enemyDirection.Normalize();

enemy.Position += enemyDirection * enemy.Speed;

}

That’s it. We run the application, and now the enemy follows you around the screen. Programming is really easy, when you think about it.

The next step is to add more enemies. This is actually a lot easier than you might think. First, let’s look at how we are currently creating instances of the Enemy class.

Creating an Enemy

enemy = newEnemy();

enemy.Avatar = txEnemy6;

enemy.Position = newVector2(600f, 200f);

enemy.Rotation = 0f;

As you can see, it takes four lines of code, and we aren’t even setting speed at this point. There are a couple of ways to condense this down, including creating a constructor, and using Object Initialization. In this case, let’s go ahead and use Object Initialization, which means that we will use the default constructor, then assign the values directly after in braces. I prefer this method in this case because when I read through the code, it is more explicit. You may prefer to use a constructor, which works just fine by me. Using Object Initialization, the previous code changes to the following:

With this setup, it’s much easier to instantiate a full new Enemy with just a single line of code.

We had been using a variable called enemy defined throughout the class. To allow for more enemies, we’ll make use of a generic collection called List. Replace the line towards the top of game1 defining enemy

This week, I’m going to go over how to break out Player and Enemy into classes, which will make it easier to handle multiple enemies, collision, AI, that sort of thing. We’ll be starting things off with the project from last week, so you can go grab that now.

If you take a look at how we’ve been doing things, you’ll notice that I have been using only the file game1.cs, which was automatically generated for me. When I added an enemy, in order to track its position, I created a variable called enemyPosition, because I was already using position for my player. If I wanted to add another enemy, I would have to do something like enemyTwoPosition or enemy2Position, and the next enemy after that would have to be enemy3Position, and it would just be a pain to have to keep track of all of those and copy all of the attributes for each new instance. It would also be a pain to have to check every instance for their collision, and to have to draw each one. If I changed something in one, I’d have to change it in all of them, and missing one of them could result in a bug that might not be noticed right away, when it would be easiest to fix. That’s why I’m going to break out the player and enemy into their own classes. I’m not going to go into subclassing, although there are a good number of shared attributes that would make it make sense to do so.

Let’s take a look at what we have, first.

Current Player and Enemy

Texture2D triangle;

Vector2 position;

float rotation;

Color triangleColor;

Texture2D enemy;

Vector2 enemyPosition;

We only have a texture and a position for the enemy, because it was static in the last article. It would make sense to add rotation to it, as well as a speed variable that will allow us to have different classes of enemies with different speeds. To begin, we’ll need to create a new class. Right click on the TriangleShooter project in the Solution Explorer, and choose Add –> Class. When it asks for a filename, type in Player.cs. Add another class, and name this one Enemy.cs. The contents of the two files is below:

Player.cs

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

namespace TriangleShooter

{

classPlayer

{

publicTexture2D Avatar { get; set; }

publicVector2 Position { get; set; }

publicfloat Rotation { get; set; }

publicfloat Speed { get; set; }

}

}

Enemy.cs

using Microsoft.Xna.Framework;

using Microsoft.Xna.Framework.Graphics;

namespace TriangleShooter

{

classEnemy

{

publicTexture2D Avatar { get; set; }

publicVector2 Position { get; set; }

publicfloat Rotation { get; set; }

publicfloat Speed { get; set; }

}

}

Essentially, they are the same thing. That’s why I said that you could do well with subclassing, but we’ll keep it like this. I also added Speed onto Player, which will be useful a bit later in the series when I get into fine-tuning your game to make it more fun to play. To take advantage of the new classes, we’ll make a few changes to the game1.cs file. Namely, we’ll modify the variable declaration, the Initalize method, LoadContent, Update, and Draw. We’re just refactoring here. No changes to how the game plays are made in this modification.

Variable Declaration

GraphicsDeviceManager graphics;

SpriteBatch spriteBatch;

Player player;

Texture2D txPlayer;

Enemy enemy;

Texture2D txEnemy6;

Color triangleColor;

int movementId = 0;

We move most of the initialization until after LoadContent, since we need to load the textures.

Continuing from last week, in this article I’ll be walking through some basic collision. Again, I’ll be starting with the code base from last week, so you can go and grab that over at my SkyDrive share.

To get started, we’ll need something to collide with. I’ve created some enemies for use with the game, which you can download from SkyDrive. I’ll start with Enemy-6.png, the one that looks like this:

To do this, add it into the TriangleShooterContent project by right-clicking the project in the Solution Explorer and choosing Add –> Existing Item, and selecting Enemy-6.png. We’ll then need to create a variable to hold the texture, and a variable to track it’s position. In a later article, we’ll add some basic AI to control it, but for now, it will be static.

Variable Declaration

Texture2D triangle;

Vector2 position;

float rotation;

Texture2D enemy;

Vector2 enemyPosition;

Initialize Position

protectedoverridevoid Initialize()

{

position = Vector2.Zero;

enemyPosition = newVector2(600f, 200f);

base.Initialize();

}

Loading Content

protectedoverridevoid LoadContent()

{

// Create a new SpriteBatch, which can be used to draw textures.

spriteBatch = newSpriteBatch(GraphicsDevice);

triangle = Content.Load<Texture2D>("Triangle");

enemy = Content.Load<Texture2D>("Enemy-6");

}

We’ll also need to add a line to the Draw method to display the enemy.

If we run the application, we now can see that there is an enemy with which we can collide.

But how can we tell if the collision has happened? How about we change the color of the triangle to red? To do this, we’ll have to add a variable to track the color, and set it to red when the collision happens.

Now we’re ready for the collision. We’ll take care of it in the Update method. To check for collision, we have a few options. The easiest would be either rectangle intersection or testing a rectangle to see if it contains a point. In this case, I’ll be using the Rectangle.Contains. The Contains method takes a Point, while our position is a Vector2, so we’ll have to do a bit of casting. We’ll also have to construct a rectangle from the position and texture we have in order to find out if it contains the point. The lines that need to be added into the Update method are as follows:

Continuing on last week’s article, this week I’ll be showing you an updated way of handling movement using multi-touch. I’ll be starting with the code base from last week, so you can go ahead and get started by downloading that from my SkyDrive share.

At the end of last week, we had a triangle that was being drawn based on a Vector2 called position. position was being updated based on the TouchPanel state. This means that wherever you touch, that’s where the triangle goes. For some games, this is what we want. But what if you wanted to build a game where you had to navigate through a maze. You start on one side, touch the exit, and bang, you win. Instead, you might want to move towards the touch point. That’s what we’ll be doing here.

To begin, we need to calculate the difference between where we are now, and where we want to be. To do this, we just subtract the current position from the touch position. Let’s create a new variable in Update called direction, and set it equal to the difference. If we added position and direction, of course, we get the touch position, so changing the update we had to the following will give you the same results we saw earlier.

Refactoring Using Direction

foreach (TouchLocation tl inTouchPanel.GetState())

{

Vector2 direction = tl.Position - position;

position += direction;

}

We don’t want to move directly to the new location, though, just in that direction. To do this, you can normalize the vector, which means that you create a new vector that points in the same direction as the original, but has a length of one. Once you’ve done that, we get the behavior we wanted.

Normalizing the Direction

foreach (TouchLocation tl inTouchPanel.GetState())

{

Vector2 direction = tl.Position - position;

direction.Normalize();

position += direction;

}

You’ll notice, though, that you move very slowly. To increase the rate of movement, you can multiply the normalized vector.

Increasing the Movement Rate

foreach (TouchLocation tl inTouchPanel.GetState())

{

Vector2 direction = tl.Position - position;

direction.Normalize();

position += direction * 10;

}

If you have a multi-touch capable computer, or if you have a Windows Phone, you can see that putting more than a single finger on the screen makes the triangle move towards both of them. Ideally, we’ll want to set up a primary touch point, and only move towards that. Luckily, touch points are identified uniquely with an int called Id. If we set up an int to track it, let’s call it movementId, we can determine whether a touch point is it, and only move if it is.

We’ll define movementId up with the other variables:

Adding movementId Variable

Texture2D triangle;

Vector2 position;

int movementId = 0;

And then modify Update down below. We’ll set the movementId on Pressed, and reset it on Released. If we didn’t reset it on Released, it would work once, then never again. It’s actually interesting to debug and check movementId each time you press on the touch panel. Each time, it increments by one. I’ve also added some code in here to prevent the wiggle you might see as the triangle jumps back and forth over the touch location. Here’s the updated code:

Updating Based on movementId

foreach (TouchLocation tl inTouchPanel.GetState())

{

if (tl.State == TouchLocationState.Pressed)

{

if (movementId == 0)

{

movementId = tl.Id;

}

}

if (tl.Id == movementId)

{

Vector2 direction = tl.Position - position;

if (direction.LengthSquared() > 100)

{

direction.Normalize();

position += direction * 10;

}

}

if (tl.State == TouchLocationState.Released)

{

if (tl.Id == movementId)

{

movementId = 0;

}

}

}

Now only the first finger down will cause movement.

You’ll notice that the triangle still just points in one direction though. That’s easy enough to address. The SpriteBatch Draw method has an overload that includes an argument of type float called rotation. If we set one of those up, we can pass that over. We’ll start by setting up a variable called rotation:

Adding rotation Variable

Texture2D triangle;

Vector2 position;

float rotation;

Then modify Update to get the rotation. We have a Vector2 we called direction, which gives us an X and a Y we can use to find an angle. If you look back at your time in trigonometry, you can remember SOH CAH TOA, Some Old Hippy Caught Another Hippy Tripping On Acid, Sine Opposite Hypotenuse, Cosine Adjacent Hypotenuse, Tangent Opposite Adjacent. Since we have X and Y, Adjacent and Opposite, we want to use Tangent. So tan(theta) = y/x, that means theta = arctan(y/x). We have to be careful here for two reasons. First of all, if X is zero, that’s division by zero, and that’s a problem. Second of all, there is a well known problem in finding out the origin quadrant of the original angle, basically, this means you don’t know the sign. I was given a solution to this when I was giving a presentation at one of the Windows Phone launch events in the Atan2 method. It basically handles all of that for you. So with that in mind, the Update code becomes:

Getting rotation

foreach (TouchLocation tl inTouchPanel.GetState())

{

if (tl.State == TouchLocationState.Pressed)

{

if (movementId == 0)

{

movementId = tl.Id;

}

}

if (tl.Id == movementId)

{

Vector2 direction = tl.Position - position;

if (direction.LengthSquared() > 100)

{

direction.Normalize();

rotation = (float)(Math.Atan2(direction.Y, direction.X));

position += direction * 10;

}

}

if (tl.State == TouchLocationState.Released)

{

if (tl.Id == movementId)

{

movementId = 0;

}

}

}

And finally, we have to modify the Draw function to make use of the new rotation information. The arguments it asks for are:

The Texture2D, triangle

A Vector2, position

A source rectangle, which will determine which portion of the texture to draw, null means the whole thing

A Color to tint the Texture2D, white will give you the unmodified texture

A float for rotation, which we pass the calculated value

A Vector2 that it will treat as the origin about which the texture will be rotated. In this case, I like it to be in the center of the back of the triangle

A scale multiplier. 1 will maintain the original size. 0 would reduce it to nothing.

SpriteEffects, which would allow you to flip the texture vertically or horizontally

A float for layerDepth, the Z-order. Since I’m only drawing one thing, 0 will work.

Welcome to the second post in the series building TriangleShooter. In this post, I will be going over drawing a sprite to the screen, then moving it around using multi-touch. In the last post, I described what you got from File –> New Project, so we didn’t have any code as such as our starting point. This means that we’ll be starting from a new project named TriangleShooter. To make this happen, open “Microsoft Visual Studio 2010 Express for Windows Phone” from the start menu and selecting File –> New Project. From the New Project dialog that comes up, choose XNA Game Studio 4.0, pick Windows Phone Game (4.0), change the name at the bottom of the dialog to TriangleShooter and click OK.

This will get you the solution we went over last time, including two projects, TriangleShooter and TriangleShooterContent. We need to add a graphic that we will draw to the screen, so we’ll start by adding that into the Content project. I’ve added the Triangle graphic to SkyDrive, so you can grab that now. Once you’ve got that, we’ll add it into the project by right clicking on the content project, and choosing Add –> Existing Item…

Navigate to wherever you extracted the Triangle.png file, select it, and click Add. It should pop up under the Content Project. You can also drag and drop into the content folder if you prefer that. At this point, let’s take a look at some of the properties of the newly added Triangle.png file. To do this, right click on the file in the solution explorer and select properties. This should pop up the properties window beneath the solution explorer.

By default, a few things are set here based on the file type. The most important one to look at is the Asset Name. That is how you will refer to the file in code when we load it. Also important are the Content Importer and Processor. These determine how the file will be treated inside of the application. In this case, it is being handled by the Texture pipeline, but you could make use of a custom importer and processor, something I’ll take a look at in a future post.

So now that we’ve got the file included in the content project, we’ll need to draw it. To begin with, we’ll create a variable to store the texture. The type will be Texture2D, and we’ll name it triangle. Place the following code inside of the Game1 class beneath the SpriteBatch declaration, so it looks like this:

Adding a variable for triangle

publicclassGame1 : Microsoft.Xna.Framework.Game

{

GraphicsDeviceManager graphics;

SpriteBatch spriteBatch;

Texture2D triangle;

Next, we need to load this content into the variable. Since we’re loading content, we’ll use the LoadContent method. Inside of LoadContent, we need to make use of the templated Content.Load method, bringing over a Texture2D with an asset name of Triangle, and put that into triangle.

Loading triangle

protectedoverridevoid LoadContent()

{

// Create a new SpriteBatch, which can be used to draw textures.

spriteBatch = newSpriteBatch(GraphicsDevice);

triangle = Content.Load<Texture2D>("Triangle");

}

Finally, we’ll need to draw it. Naturally, we’ll do this in the Draw method. We’ll make use of the SpriteBatch, which allows you to queue up a bunch of draw commands for efficiency. It does this by requiring a call to Begin at the beginning, and End when you’re done. Between those calls come all of your drawing code. The SpriteBatch’s Draw function is highly overloaded. We’ll use the overload that takes a Texture2D, a Vector2, and a Color. The Texture2D is what you want to draw, the Vector2 is where you want the top left corner of the graphic to be, and the Color is a tint applied to the graphic. In this case, we’ll draw the triangle, draw it in the top left of the display, and tint it white, which won’t change the color.

Drawing the Triangle

protectedoverridevoid Draw(GameTime gameTime)

{

GraphicsDevice.Clear(Color.CornflowerBlue);

spriteBatch.Begin();

spriteBatch.Draw(triangle, Vector2.Zero, Color.White);

spriteBatch.End();

base.Draw(gameTime);

}

If you run the code now, this is what you’ll see:

Looks good! There are a couple of changes we should make before going any further, though. First of all, I want this application to be full screen. To do this, I’ll add a line of code to the constructor, telling it that I want the graphics to be displayed in full screen mode.

Switching to Full Screen

public Game1()

{

graphics = newGraphicsDeviceManager(this);

Content.RootDirectory = "Content";

graphics.IsFullScreen = true;

// Frame rate is 30 fps by default for Windows Phone.

TargetElapsedTime = TimeSpan.FromTicks(333333);

}

Secondly, let’s change the background color to black. It adds a more spacey feel to the game. We’ll just change the line of code that clears the screen down in the Draw method to clear using Color.Black instead of Color.CornflowerBlue.

Clearing the Screen with Black

protectedoverridevoid Draw(GameTime gameTime)

{

GraphicsDevice.Clear(Color.Black);

Now when you run the program, it looks a bit better:

For the last bit of this post, I’ll show you how to make the Triangle move around using multi-touch. We’ll start by adding another variable to the class to track position, called position. It will be of type Vector2, to hold the top left of the graphic. We’ll put it directly after the declaration of the triangle, like so:

Adding the position Variable

Texture2D triangle;

Vector2 position;

We then need to give it a default value. Since we’re not actually loading it from anywhere, it won’t go into LoadContent, instead it goes into the Initialize method.

Initializing position

protectedoverridevoid Initialize()

{

position = Vector2.Zero;

base.Initialize();

}

Then, we modify the line of code that draws the triangle to make use of position, replacing Vector2.Zero with position.

Using position in Draw

spriteBatch.Begin();

spriteBatch.Draw(triangle, position, Color.White);

spriteBatch.End();

If we run now, we get the same behavior as we did before. This makes sense, because we’re not actually updating the position anywhere. To update the variable, we’ll want to add some code into the Update method. Specifically, we’ll go through the active touch points and set position to their position. In the next post, I’ll go into a method of finding out which touch point is the primary (first) touch point, and only updating using it, but for now, we’ll just update it using whatever touch point gets there. To do this, we’ll just loop through each of the touch points using a foreach loop and set the position, as so:

And that’s it! Run the program, and you can move the triangle around with your finger (or mouse, in the emulator). If you have a multitouch display or a Windows Phone 7, you can see what happens when you put more than one finger on the screen. Essentially, it updates to each of the touch points, which means whichever was the last one down will be where the triangle goes.