Chapter 6: 2D Games and XNA
In this chapter we'll start to make our first XNA programs, which will just display pictures on our screen. But before this we'll cover a little bit of theory. We'll keep things short, but we'll go over a bit of 2D math including XNA's 2D coordinate system and vectors. Then we'll take a look at some important game programming concepts and at how sprites work in XNA. Specifically we'll cover:
l How the coordinate system in 2D in XNA works
l Learn the basic properties of sprites
l Create a “Hello World!” type of XNA program
l Draw a sprite onscreen in XNA
2D Graphics Theory
Coordinate System
The most basic thing to do when creating 2D games is to draw various pictures on the screen. To do this we need a way of setting locations for pictures on the screen. If we want to put a picture of a spaceship in the lower center of our screen, how do we say where that is precisely to the computer? You probably remember from school learning about the Cartesian coordinate system. In this system we have two coordinate lines, axises, one that runs vertically called the y axis and another that runs across is the x axis. It looks like this:

We specify a point, which is just a location, by writing its x and y coordinate, (x,y). The point where the x and y axises cross is called the origin. Points can be negative or positive numbers, depending on where they are at in the grid.
To draw our 2D graphics on the screen we're going to use a similar system; we'll specify locations of all of our graphics using a Cartesian grid with units (units are how for apart each number is) of pixels on the screen. But there is one big difference between our graphics grid and a regular one: the coordinate system for our screen will have the origin in the upper left corner and the positive x-axis going to the right (which is usual) but the positive y-axis starts in the upper left corner and goes down the screen:

We can think of this grid as just a vertical “flip” of the regular coordinate system. So the point (10,10) is 10 pixels from the left side of the window and 10 pixels from the top. Using this kind of reversed coordinate system isn't anything special about XNA, almost all 2D graphics system use it. At first it can be a little unusual, but it soon becomes natural.
And even though the origin for our coordinate system is in the upper left corner of the screen, there are still negative axises, they're just off screen and can't be seen. For example, let's say that we have a picture that is 100 pixels by 100 pixels and we want to have half of the picture in the top corner of the screen it the picture would be at -50, -50 to 50, 50:

Vectors
Now that we have our coordinate system set up, we need to talk about points and how they are set. When programming with sprites in XNA we technically won't be using points to describe their location, we'll be using vectors. Vectors are mathematical objects that are similar to points except that they don't just describe a location but they also have a magnitude (distance.) We can think of them as a ray from one point to another:

The illustration above shows the vector AB. In most of our 2D programming we'll be using vectors where the first point is at the origin:

You'll notice that this vector is used in a way similar to a point. All it is doing is describing a location (in this section we'll use the term vectors to really mean points.) So why use vectors? The main reason is that vectors are really much more powerful than points. We can do a lot more things with them, especially in 3D. And since the vectors we use to describe location are going to start at the origin and they'll have the same coordinates as points there is no need for a distinct point class. XNA could have created a separate point class to use instead of vectors, but most of the code would be redundant and it would get unnecessarily messy scattered with points and vectors.
How we use vectors in XNA is pretty simple. XNA has objects built in for vectors in two, three, or four dimensions (for some 3D math transformations 4D vectors are needed.) These vectors carry floats for each component. To declare a vector variable we use the Vector keyword followed by its dimension:
Vector2 playerPosition;
To initialize it:
playerPosition = new Vector2( 50.0f, 50.0f );
We can set and access its x and y:
playerPosition.X = 75.0f;
playerPosition.Y = 75.0f;
And we can perform many standard math functions on vectors (adding, subtracting, multiplying, ...)
There are also some defined vectors for standard positions, such as Vector2.Zero for a (0.0f, 0.0f) vector.
Game Programming 101
We just looked a little about the geometry of 2D games, let's look a bit at some game programming concepts.
Game Loop
Video games are a form of interactive computer graphics, meaning that the graphics can be changed in response to input (for instance moving a player around with a controller changes what graphics are drawn on screen.) Of course not all computer graphics are interactive, such as graphics for special effects for movies. Special effects can take a long time to render, maybe hours for a single frame. Graphics for video games must be rendered much quicker, at least 30 frames per second (preferably 60). That's why graphics for movies look so much better than graphics in video games. In movies we can take as long as we like to draw a frame, but a frame for a video game only has one sixtieth of a second to draw everything, and that's not counting time for other non-graphics things such as physics or AI. Since video games are constantly updating (for the interaction) they are designed based on giant loop, a loop that constantly updates everything in the game. The loop can look like the following:
while ( Game is Running )
Check for input (keyboard, mouse, controller)
Update Entities in the game (player, enemy)
Update Physics
Update Collision Detection
Draw Scene
end while
This loop only has a few things in it, a real game loop includes all kinds of items, such as checking for network messages or collision detection. The overall speed of the game loop is measured in the number of frames that are rendered each second (frames per second or FPS). This is also referred as Hertz, Hz. A game working at 30 frames per second could be said to be running at 30Hz. The default speed for XNA games is 60Hz, but we can change this if we want to (or it can change if we don't want to, such as if someone with an older computer tries to run our game and they can't update that fast.) We'll see the loops we'll use in our game in our first XNA program later in this chapter.
Finite State Machines
Another concept important to game programming is the idea of describing things in terms of finite state machines. A finite state machine (FSM) is just a fancy term for describing things in terms of various “states” they can be in. For instance, let's say we're making a first person shooter game and we have an enemy class for creatures we encounter. An enemy creature could be walking around, or attacking us, or dead and just laying there. We can describe this enemy as a FSM, with states of walking, attacking, or dead. When we go to update the entity in the game we'll change it based on the state the enemy is in. (Like if the enemy is in the walking state we'll have it move, but if it's in the dead state it won't.)
Thinking of things in terms of FSMs makes the entire game design easier. Even a game itself can be thought of as a state machine; the typical game has states such as PLAYING, PAUSED, GAME_OVER, SPLASH_SCREEN. Sometimes when programming these state machines the states will be very explicit. When updating the enemy creature we could have a case statement or series of if's to see which state the enemy is in:
if( state == WALKING )
// walking code
else if( state == ATTACKING )
// attack player code
else if( state == DEAD )
// Do nothing
and somewhere else we have a function that chooses the value of the state variable for the entity at each update. Or sometimes we keep the conceptual idea of the various states, but in the code it is not spelled out so much. The above code could look like:
if( enemyHealth == 0 )
return; // If destroyed, exit
if( playerDistance < 10 )
// Attack code
else
// walking code
In this case we use the idea of states, but not explicitly. When creating a design for your games be sure to think of the different objects and the different states they can be in.
Graphics VS. Logic
I come from a background of programming graphics, so it's easy for me to think of game programming as a special case of creating graphics. But most of the work that goes into programming a game is not in it's graphics. There are huge areas of programming games that have nothing to do with graphics, such as play control, physics, and artificial intelligence, to just name a few. But graphics are a major portion of any video game, and they tend to use a lot of resources. One of the things we do in game programming is to make a separation of programming logic, which isn't graphics, and the programming (rendering) of the graphics themselves. XNA even has two game loops, one for just updating the graphics and another for everything else. The graphics loop is:
protected override void Draw(GameTime gameTime)
Which will just have code for rendering everything, and the update loop is:
protected override void Update(GameTime gameTime)
which will contain logical updates, such as checking input. We'll talk more about these in a moment. Note the two loops run asynchronously, which means that it is not the case that the update loop updates, then the drawing loop updates, then the update again. Instead they run separately, both running independently (but still at roughly the same rate.)
Sprites
We've covered some math and game concepts, let's look at sprites. The 2D game we'll make in this book is a sprite based game. Sprites are bitmap images, just regular pictures, that we can move and do different effects on screen with. (Note the term sprites often mean a series of multiple pictures, like a little sequence of animation, but in XNA the term means a static image.) Sprites are raster images, like photographs, which means that each pixel of the image is stored in memory. Not all 2D games use sprites for their pictures, some use vector graphics. Vector graphics store programmed painting commands to draw the picture and so individual pixels of the image aren't stored in memory. Traditionally 2D games have been made with sprites, but some platforms like Macromedia's Flash use the programmed vector graphics. Sprites give much more detail and more realistic images, and we won't be using vector images in this book. All of the older scroller games from platforms such as the older Segas and Nintendos were made with sprites. We can do a lot with sprites, and we'll cover some basic concepts of them here.
Before we get into sprites here are two notes. First in XNA the documentation calls our pictures sprites, but in the code itself they are called textures (specifically Texture2D objects) which are standard picture files used in graphics. Also note the dimensions of a sprite are just its size measured in pixels. We say this as width by height (and write it as width x height). So a sprite 300 pixels wide and 200 pixels high is a 300 by 200, or 300 x 200 sprite.
Sprite Positioning
We'll position sprites in our game using the coordinate system described before. One thing we need to think about when positioning sprites on the screen is the sprite origin, which is just a specific location on the sprite, that when we tell XNA to draw it puts the sprite there. If we have a sprite that is 200 x 200 and it has a sprite origin of (0,0) if we tell XNA to draw it at point (200.200) it will look like:

But that may not be what we want. If we have a player picture and we want to say “draw the player at position (200,200)” we probably want the player picture to be centered at point (200,200), not have the upper left corner there. Since our picture is 200 x 200, if we put the sprite origin at (100, 100), the center of it, the sprite will be drawn like this:

Which makes sense that the location we specify is at the center. By default the sprite origin is the upper left corner of the sprite, but often we'll set it to the center of a sprite. The sprite origin is just something to keep in mind when drawing sprites, so we don't get unexpected results.
Rotation, Translation, and Scale
The three main things we can do to a sprite in our game our translate it, rotate it, or scale it. Translation means to move the sprite to a different position, rotation means to put a “spin” on it, and scaling a sprite is just shrinking or stretching it. These basic operations, translate, rotate, and scale, are the three basic things we can do to all graphical objects. This is true for 3D graphical objects as well. Usually these operations are done using matrices, but we'll translate rotate and scale using prebuilt functions. And to keep things even simpler we'll assume that the sprites that we use for our games will be made in the size we want already, so we won't be scaling the sprites in our games.
Sprite Alpha and Tinting
All of the pictures that we use for our sprites will be bitmap (.bmp), targa (.tga), .jpeg or .png files. These files are always rectangular, but obviously we want to draw pictures on the screen that aren't rectangles. If we're drawing a spaceship on screen we want the picture to be the shape of the ship, not a rectangle. We can assign parts of the picture an alpha value, a level of transparency in the image. The alpha parts won't be drawn, or can be drawn as partially transparent. This lets us render sprites of different shapes. Also, besides giving the sprites an alpha value we can also tint the sprite, which means giving it an extra overlay color. If we don't want to tint the sprite we can just “tint” it white.
Sprite Depth
When we render sprites on the screen the order in which they are drawn is important. If we have a large background sprite and a smaller spaceship sprite that supposed to go on top of it we would be in trouble if the spaceship sprite was drawn first and the background sprite was drawn on top of it (we wouldn't be able to see the ship.) XNA by default uses what is called a painter’s algorithm, where the first things listed are drawn first and later drawing commands draw things on top of the earlier one. We can keep track of what sprites should go on top of each other ourselves; we can just give each sprite a depth. The sprite depth is a decimal number between zero and one. With sprites closer to zero being drawn last (on top of other sprites) and sprites closer to one being drawn first (on the “back” of the screen.) For our spaceship sprite we can give it a depth of zero and our background a depth of one and everything will be drawn correctly.
Sprite Batching
When we render sprites on screen, we don't just tell the computer to render them one at a time. Instead what we have to do is put sprites in groups called sprite batches. Then to render sprites we render the batch of them. There are a lot of good reasons for drawing sprites this way. It can make the process of drawing them faster since they all are rendered at the same time, and easier to program since we can specify options for how they are to be drawn to whole groups of sprites instead of one at a time. We can also use multiple batches to group sprites together logically. For example, later on we'll be using one batch for the background, a second for the main game elements (player,enemy) and a third for any HUD text.
Hello World! XNA
Finally, we are going to start some programming. Just like we did with C# we'll make an XNA version of Hello World!, except we won't have it print out anything on the screen and we won't add any code to do anything; the only thing it will do is show the default blank screen. Even though we'll just be using the default XNA code we'll go through it line by line and see what's going on.
To create an XNA program start XNA Game Studio and Goto file->New Project. Then select Windows Game (3.1) and type the name HelloWorldXNA for it.

This will create an XNA project and some code will be automatically generated for it. The following code (minus some comments) is here:
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace HelloWorldXNA
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
// TODO: use this.Content to load your game content here
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
// TODO: Add your update logic here
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// TODO: Add your drawing code here
base.Draw(gameTime);
}
}
}
If you Goto Debugging->Start Debugging or hit F5 you'll see the following screen appear:

This may not be much, but if you tried writing C++/DirectX code to just put a window on the screen like this you might have to write up to a 100 lines. Now let's analyze the code. Notice in the first part besides the regular .Net C# using directives we now have using statements for the XNA framework as well.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
These are all the using directives we need to have access to the complete XNA framework. You could go through these and see what each one is in the XNA documentation. Remember that in any file where you need to use any XNA classes copy these using directives.
The game itself is in the relevantly named Game class:
public class Game1 : Microsoft.Xna.Framework.Game
Which is a basic framework for a game. All of the games we make with XNA will be inside this class. Notice the code doesn't have a main function like all of our Console programs in the previous part of the book. That's because the Game class takes care of starting and running our program. The game class starts with two data members:
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
The graphics is the graphics device manager and is a very important object. It handles the underlying graphics device that actually draws (renders) everything on screen. We'll modify the graphics device when we want to change the way things are displayed, such as switching our game from windowed mode to full screen. The other member is a SpriteBatch, which as is a batch used for drawing groups of sprites.
After these declarations we find our game class constructor, Game1(). The game constructor just initializes the graphics device manager and sets the name of the directory that all of our game content (sprites, sounds, etc) will be found in:
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
After this is an initialization method:
protected override void Initialize();
which if we need to do some things (like calculations) before our game officially starts up we can put them there. We can also load any non graphics content there. The next method:
protected override void LoadContent()
is a place to load any graphics resources before the game starts. This will be a very important method; eventually we'll be adding a lot of graphics content and it will all be done here. The following method
protected override void UnloadContent()
Lets us unload any graphics content when the game exits to release it out of memory. We won’t be modifying this method.
After this we have two more methods:
protected override void Update(GameTime gameTime)
protected override void Draw(GameTime gameTime)
These are the game’s two main update loops we talked about before. These two loops will be running all the time. Just to go over again, the Update loop is where we update all of the game logic and the Draw loop is where we draw everything on the screen. Each of these is passed an instance of the GameTime class, which tells us things about how much time has passed since the last time the loop was run. (This is helpful for many things, like physics calculations.)
By default the update loop has a line to test if the game has exited, and the Draw loop has a graphics command:
GraphicsDevice.Clear(Color.CornflowerBlue);
The one graphics line clears the screen to the color Cornflower blue (if you don't like this color you can delete it and type in a different color such as White. To see a list of colors delete the period after Color and write it again and Intellisense, Visual Studio's syntax helper, will display a list of available colors.) The graphics device is cleared at each update of the graphics loop, and then we have one sixtieth of a second to draw everything in our game.
Adding a Sprite
We have created our first XNA program, but it doesn't really do much. So let's get started with sprites and add in a big background sprite, that covers the whole the whole window. To do this we'll add in an object for a Sprite.
Go ahead and make a new project for this program. In C#, goto File -> New Project and select Windows Game (3.1). Name the project SpriteDisplay and note the folder it is being saved in:

The reason to pay attention to the location the project is saved in is because we need to copy our artwork to the content folder there. Get the spaceBackground.bmp file either from the samples on xnagamemaking.com. Copy the artwork to the content folder inside the folder of the project. For example, using the path C:\Resources above we would copy the picture to C:\Resources\SpriteDislay \SpriteDisplay\Content. With the artwork in the correct location we can then add it to our project.
Right click on Content folder in the solution explorer on the right side of Visual C# and select Add.. -> New Item... Then select spaceBackground.tga and click OK. This adds the sprite to our project.
Now our artwork is setup and onto the sprite code. When we start adding things to our game class in XNA we'll typically do four things:
1. Declare the variable
2. Initialize the variable, usually in the LoadContent() method
3. Add the item to our Draw loop so we can see it on screen
4. Add the item to our Update loop so we can do any logic updates
on it
For now we are only going to be creating a sprite (the sprite batch is already created for us). It won't need any update logic so we'll only be doing the first three things.
First we'll declare the variable. Just before the main Game1 class and after the spriteBatch definition add the following line:
Texture2D spaceTexture;
Now that we have the sprite defined we'll need to initialize it, so change the LoadContent method to
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spaceTexture = Content.Load<Texture2D>("spaceBackground");
}
The SpriteBatch initialization is pretty simple; all we do need to do to create it is pass it our graphics device. The syntax
spriteBatchName = new SpriteBatch(GraphicsDevice);
will be the same for any additional sprite batches we create.
To create the sprite we call the content manager to load it and pass it the name of our texture resource. The content manager is an object that loads all of the art data, not just sprites. The basic syntax for it is:
Content.Load<ResourceType>("assetName");
Where ResourceType is the type of content we're loading, such as a texture or 3D model, and assetName is the name of our asset. Assets are just the name of the file (without any extension). This syntax will also be used for loading all of our sprites, so the line is worth remembering.
We have the sprite loaded, next let's draw it onscreen. This is a large texture that fills up everything so we'll just position it in the upper left hand corner.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(spaceTexture, Vector2.Zero, Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
To draw our sprite batches we first start them by calling the method Begin(). After this we call all of our command, to draw the sprites. Then at the end of the SpriteBatch we call .End(), which actually draws everything on the screen.
The spaceBatch.Draw() draws the texture. The syntax for it is:
spriteBatch.Draw( spriteName, positionVector, tintColor );
The first parameter is the name of the texture to draw. The second parameter is where we want the position of the upper left corner of the sprite to be at. (Again here we put (0,0) for the upper left corner.) The last parameter is for tinting, which we don't want so we'll just set the tint to white.
Go ahead and build/run the program by going to Debug->Start Debugging or hitting F5. You'll see the sprite fill up the screen:

And now we have a program that draws a sprite on the screen. Try changing the Vector2.Zero in the draw method to change the position of the sprite. In the next chapter we'll talk about how to put the other sprite attributes we mentioned (sprite depth, sprite origin...) in XNA code.
Summary
We have two XNA programs under our belt. In the next chapter we'll start making the Ship Fighter game, by creating a separate player class for the game and then take in input from the keyboard and Xbox controller to move the sprite around.
