University of the West of England, Bristol

Department of Computer Science and Creative Technologies


C# XNA Worksheet 1 - Simple Sprite Manipulation in XNA

C# 2010 - XNA Version 4


Learning Aims

This worksheet shows you how to create a very simple C#/XNA application which moves and rotates simple sprite images. This application will be too simple to be regarded as a proper game.

When you've completed this worksheet, you should be able to:

To get the most out of this worksheet you should do the following:


If You Get Interrupted

If you are unable to finish any of these worksheets in one go, then this is what you should do to make sure that you can resume it from the point you finished, without having to start from scratch:


Practical Steps- What You Have to Do

Worksheet Assets

You will need to download and unzip these graphical assets for use in these worksheets:

Graphical Assets

Getting Started

It is important to follow these steps closely. If you get stuck then you should ask your teacher (or one of your friends). If several of you get stuck then you really should tell the teacher as it probably means there's a problem with the worksheet!

Here's what we want you to do. We suggest that you put a tick beside each step as you complete it.

  1. Start Visual Studio/Visual C# Express/XNA Game Studio
  2. From the menu, select File > New Project:
  3. When the New Project window appears, click once on Windows Game from the list of project types. Don't double-click on it and don't click on OK yet!
    In the Name field type MyFirstGame:
  4. Click on OK
  5. The main window now opens and should look something like this:

    Look carefully at the right hand window frame you'll see an entry named Game1.cs, this file contains the statements for your program. These statements are visible in the left hand frame. To give you a head start, when you create a new project you get a game skeleton for free!

Loading a Sprite Image

The next step is to select a sprite image and load it into XNA Game Studio. This process triggers an XNA feature called the Content Pipeline which loads the file into your project so that it's available to the game.

  1. On the right hand side of the project window you'll find a frame called the Solution Explorer. A few lines down into this frame you'll see "MyFirstGameContent (Content)".
  2. Right click on MyFirstGameContent (Content) and select Add > Existing Item...
  3. A file chooser now pops up. You should navigate to the place where you stored the image files for this worksheet and select the file named Balloon.png and then click on Add

    XNA Game Studio now loads the file into the project and its name now appears in the Content section of the Solution Explorer. Interestingly, although the file was originally in PNG format, the XNA content pipeline changes it to a completely different format

  4. We can examine the properties of the image by right clicking on the file name and selecting Properties:
  5. The properties window opens up below the Solution Explorer:

    Notice that the Asset Name for this image is "Balloon" and not "Balloon.png". Now that the file has been loaded into the XNA Content Pipeline, it is no longer necessary to remember that its original format was PNG.

Displaying the Sprite Image

Although we've loaded the sprite image into the project, we need to make some additions to the game skeleton for this project. We need to make changes in three places to make the sprite visible.

  1. The code for the file named Game1.cs should be visible in the left hand side of the project window. If it isn't visible then click on the tab named "Game1.cs" near the top of the window.
  2. Find the chunk of code near the top of the file which says:
      public class Game1 : Microsoft.Xna.Framework.Game
      {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
    
  3. Insert the following just after the spriteBatch line:
        Texture2D balloonTexture;
    

    This defines a field of this class into which we will store the sprite bitmap.

  4. Scroll down "Game1.cs" until you find the LoadContent() method.
  5. Insert this line of code just following the TODO comment line:
         balloonTexture = this.Content.Load<Texture2D>("Balloon");
    

    Notice that the IDE tries to help you as you type. For example, when you type the first few letters of balloonTexture, a window pops up offering a list of suggested completions. Just scroll down to the correct word and press TAB to enter it into the file. In this way you can enter most of the line without having to type all the words in full, except for the final quoted "Balloon".

    Also note that the quoted name is "Balloon" and not "Balloon.png". This is the Asset Name property which we saw earlier.

  6. Finally, we must tell the program where to draw the sprite on the display. Scroll down to the Draw() method and put the following lines after the TODO comment:
        // TODO: Add your drawing code here
        spriteBatch.Begin();
        Vector2 position = new Vector2(100, 200);
        spriteBatch.Draw(balloonTexture, position, Color.White);
        spriteBatch.End();
    
  7. Compile and run the program. The easiest way is to click in the arrow symbol next to the word Debug (circled in red):

    The program starts and, all being well, should open up a game window showing a single red balloon:

    This isn't particularly exciting but it's a start...

  8. Close down the game by clicking on the X at the top right of the game window. Note that the mouse cursor is not visible when it's inside the game window

Making It Move

We can liven up the program by making the sprite move about the screen. To do this we first create class fields for the sprite's X and Y positions, and change the Vector2 position object that we set up in the Draw() method. We can change the sprite's X and Y positions within the Update() method.

  1. Scroll up to the top of the Game1.cs file and find the line that you inserted to define balloonTexture:
        Texture2D balloonTexture;
    
  2. Modify this section so it looks like this:
        Texture2D balloonTexture;
        int balloonX = 400, balloonY = 300;
    
  3. Scroll down to the Draw() method and modify it so that it looks like this:
        // TODO: Add your drawing code here
        spriteBatch.Begin();
        Vector2 position = new Vector2(balloonX, balloonY);
        spriteBatch.Draw(balloonTexture, position, Color.White);
        spriteBatch.End();
    
  4. Run the program as before. Once again you should see the balloon on screen, but in a slightly different position.
  5. To make the sprite move, we need to change its X and/or Y position values. The place to do this is in the Update() method which is guaranteed to be called 60 times per second.

  6. Scroll upwards to the Update() method and put in the following line after the TODO comment.
        // TODO: Add your update logic here
        balloonY -= 1;
    

    This will have the effect of subtracting 1 from the sprite's Y position, thus moving the sprite upwards at the rate of 1 pixel per update (or 60 pixels per second).

  7. Run the program again and see the effect.
  8. Try adding or subtracting various amounts from the sprite X and Y positions on each update, and see what effect it has on the sprite. What is the minimum speed you can get using a simple addition or subtraction?
  9. Modify the program so that the sprite moves upwards at the minimum speed.

Redefining the Data Type for X and Y Positions

No doubt you discovered that a sprite can either be stationary, or moving at exactly 1, 2, 3... pixels per update (60, 120, 180... pixels per second). This is quite a coarse setting and it would be quite a limitation if our games were restricted to these speeds.

The problem occurs because we've specified the X and Y positions as int values; if we were to use a floating point value then we could add a fractional value at each update and obtain slower speeds. This faces us with a problem: do we define the sprite's positions as double or float? There is no obvious or overwhelming reason to use one and not the other, so in the end we must make an arbitrary decision. In these worksheets we'll use double whilst noting that we can make all our games work just as well using float. Once we've made a decision we should stick with it - it would be a recipe for chaos to use double and float in the same program!

  1. Revisit the declarations for balloonX and balloonY; change the data type to double
  2. Try running the program. You will get compilation errors in the Draw() method since the constructor for the Vector2 position object doesn't like doubles and actually wants floats! We can keep it happy by type casting the positions to float like this:
        // TODO: Add your drawing code here
        spriteBatch.Begin();
        Vector2 position = new Vector2((float) balloonX, (float) balloonY);  // Type casts to float
        spriteBatch.Draw(balloonTexture, position, Color.White);
        spriteBatch.End();
    

    Right now you might be thinking that we made the wrong decision to use double; if we'd use float then we wouldn't need the type casts. In this case you're right, but there are situations where it looks like float is the wrong decision and double is better! Having made the decision to use double, the best thing is to stick with it and accept we're going be putting type casts around the place.

  3. Modify the Update() method so that the sprite's upward velocity is now 0.5 pixels per update:
        // TODO: Add your update logic here
        balloonY -= 0.5;
    
  4. Experiment with different X and Y velocities, making sure you use both integer and non-integer values.

Adding a Second Sprite

For this part of the worksheet, we'll no longer give you step-by-step instructions. Instead we'll suggest more activities for you to do to consolidate what you've learned so far. DO NOT SKIP OR SKIMP ON THIS SECTION. It's easy to follow instructions and this can lead you to a mis-placed confidence. You need to repeat an activity several times to ensure that you can remember what to do.

Activities:

  1. Load the Dart sprite image into the Content section of XNA Game Studio.
  2. Create a Texture2D field name dartTexture, together with fields for its X and Y position, called dartX and dartY
  3. Add a statement to load the dart graphic into the Texture2D field
  4. Add statements to the Draw() method to draw the dart sprite.
  5. Add statements to the Update() method to move the sprite around the screen at a fixed velocity.

Rotating the Sprite

You may have noticed that the auto-completion feature of XNA Game Studio offers seven different options for the spriteBatch.Draw() method. So far we've been using one of the simpler versions, but now it's time to use one of the more complex versions

The complex spriteBatch.Draw() methods offer special options for drawing a sprite. These options include horizontal and vertical flipping, increasing or decreasing the sprite size, and rotating the sprite. Let's look at how we rotate the sprite graphic.

Here is the version of the spriteBatch.Draw() method we'll need:

  spriteBatch.Draw(dartTexture, position, null, Color.White, 
                   (float) dartRotation, origin, 1.0F, SpriteEffects.None, 0.5F);

The parameter we're most concerned about here is the (float) dartRotation. This specifies an angle which XNA will draw the sprite.

However, by itself this is insufficient, we still need to define an axis of rotation. This will enable us to choose a particular pixel inside the sprite image around which all the others will rotate. This is specified by the Vector2 origin. Since the dart image is 48x96 pixels, we'll set the origin to the centre point: 24, 48.

  1. Add a new field to the class, close to the fields you've defined for the dart sprite:
      double dartRotation = 1;
    
  2. In the Draw() method, remove the call to spriteBatch.Draw() which draws the dart image and replace it by these two statements:
      Vector2 origin = new Vector2(24, 48);    // Image centre point
      spriteBatch.Draw(dartTexture, position, null, Color.White, 
                       (float) dartRotation, origin, 1.0F, SpriteEffects.None, 0.5F);
    
  3. Run the program. You should see the dart tilted to the right at an angle of approximately 60 degrees.

    Note that it is standard for computer systems to measure degrees using Radians and not degrees. One radian is approximately 57 degrees.

  4. Modify the Update() method so that the value for dartRotation is changed by a small amount each time, causing the dart to rotate. Be sure to use a small value (say 0.05) or the sprite will appear to rotate very quickly and you will be faced with aliasing effects.
  5. Modify the values within the dart's Vector2 origin so that rotation takes place around a different pixel. What happens if either of the values are negative, or greater than the actual size of the image (48x96)?

Tidying Up When You've Finished

When you've finished all the steps above, you need to close down XNA Game Studio as follows:


Background Reading

Some of you may never have heard of radians before. Most serious scientists, engineers and mathematicians don't use degrees to measure angles, they use radians. This is because they are much easier than degrees to manipulate mathematically.

If you're not familiar with the concept then you should spend half an hour or so reading up about them. Good places to start are:


Return to home page