DEFCOM1  
 

 

XNA Level 1 Lesson 9

Using Sprite Sheets

  1. Add the ufoSpritesheet to the project
  2. Create ufoSpriteNum variable in the global variables section
  3. Create a ufoWidth variable in the global variables section
  4. Load the ufospritesheet graphic
  5. Edit the updateGame function
  6. Edit the draw function

 

What are Sprite Sheets?

Sprite sheets are a single image which store a number of smaller images to be used in our games.

They allow us to simply load 1 image and then select the portion we want to draw on screen.

This makes it much easier to show somebody walking on screen or for making a tile based game

Examples...

 

For now we are just going to use a spritesheet with a single row

IMPORTANT. My sprites are 128 pixels apart, if you make your own you will need to edit the code to your width.

 

Add the ufoSpritesheet to the project

Right Click on your project content menu and add your sprite sheet to the project

 

Create 2 new variables ufoSpriteNum and ufoWidth in the global varaiable sections of your code (just before the public Game1() function)

int ufoSpriteNum = 0;
int ufoWidth = 128;

//public Game1()

The ufoSpriteNum tells the game which image to draw from our sheet (starting at 0)

The ufoWidth tells the game how much of the image we want to draw

 

Load the ufospritesheet graphic

You need to go to your loadcontent folder and edit the line that loads the ufo texture

from this

//load our graphic
ufoTex = Content.Load<Texture2D>("ufo");

to this

//load our graphic
ufoTex = Content.Load<Texture2D>("ufoSpriteSheet");

 

Edit the updateGame function

No we need to tell our game which image to use depending on keypress

go to the updateGame function and add the new lines

 

//update ufo
KeyboardState key = Keyboard.GetState();
            
ufoSpriteNum = 0; //new line
if (key.IsKeyDown(Keys.Left) && ufoPos.X > 0)
{
    ufoPos.X -= 5;
    ufoSpriteNum = 1; //new line
}
if (key.IsKeyDown(Keys.Right) && ufoPos.X < 800 - ufoWidth)
{
    ufoPos.X += 5;
    ufoSpriteNum = 2; //new line
}

 

Also note I have changed any use of ufoTex.Width to ufoWidth as ufoText.Width is 3 times wider than the ufo itself.

I just used the find and replace tool

 

Edit the draw function

Finally... edit your draw function. Go to the draw main game bit and change the line that draws the ufo

from this

spriteBatch.Draw(ufoTex, ufoPos, Color.White);

 

to..

spriteBatch.Draw(ufoTex, ufoPos, new Rectangle(ufoSpriteNum*ufoWidth , 0, 128, 128), Color.White);

 

We have added a Rectangle to the function. the rectangle tells the game which portion of the main image to draw

Rectangle(X, Y, width, height)

In our code we use multiply ufoSpriteNum by the width of the ufo to draw the portion we want

 

Complete listings

public class Game1 : Microsoft.Xna.Framework.Game
{
    //----
    //Global Variables
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //screen size
    public int screenHeight;
    public int screenWidth;

    public int gameState = 0;

    // This is a texture we can render.
    Texture2D ufoTex;
    Texture2D asteroidTex;

    SpriteFont font;

    // Set the coordinates to draw the sprite at.
    Vector2 ufoPos = Vector2.Zero;

    //create an array of 10 asteroid coordinates (we will use the same image for each one)
    static int numberOfAsteroids = 25;
    Vector2[] asteroid = new Vector2[numberOfAsteroids];

    Random rand = new Random();

    int score = 0;

    int ufoSpriteNum = 0;
    int ufoWidth = 128;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }


    protected override void Initialize()
    {
        //set Screen size
        screenWidth = 800;
        screenHeight = 600;

        graphics.PreferredBackBufferWidth = screenWidth;
        graphics.PreferredBackBufferHeight = screenHeight;

        graphics.IsFullScreen = false;
        graphics.ApplyChanges();

        resetGame();

        base.Initialize();
    }

    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //load our graphic
        ufoTex = Content.Load<Texture2D>("ufoSpriteSheet");

        asteroidTex = Content.Load<Texture2D>("asteroid");

        font = Content.Load<SpriteFont>("mainFont");

    }


    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    public void resetGame()
    {
        //reset game
        gameState = 0;
        score = 0;

        //ufo starting position
        ufoPos.Y = screenHeight - 128;    //height of screen - hieght of ufo


        //Starting Position of all asteroids
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            asteroid[i].X = rand.Next(800 - 128); //position within screen width - ufo width
            asteroid[i].Y = 0 - ((i * 250) + 128);
            float y = asteroid[i].Y;
        }
    }

    protected override void Update(GameTime gameTime)
    {

        //gameState Menu
        switch (gameState)
        {
            case 0:
                UpdateMenu(gameTime);   //intro screen
                break;

            case 1:
                UpdateGame(gameTime);   //main game
                break;

            case 2:
                UpdateGameOver(gameTime); //End OF Game
                break;

            default:
                /*error*/
                break;
        };


        base.Update(gameTime);
    }

    public void UpdateMenu(GameTime gameTime)
    {

        KeyboardState key = Keyboard.GetState();

        if (key.IsKeyDown(Keys.Space))
        {
            gameState = 1;
        }
    }

    public void UpdateGame(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here



        //update all asteroid positions
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            asteroid[i].Y += 5;
            if (asteroid[i].Y > screenHeight)
            {
                Random rand = new Random();
                asteroid[i].X = rand.Next(screenWidth - asteroidTex.Width);
                asteroid[i].Y = 0 - (numberOfAsteroids * (250 - score / 10)) - 128;  //put to top
                score += 10;
            }
        }


        //Get Midpoint of ufo
        int x = (int)ufoPos.X + (ufoWidth / 2);
        int y = (int)ufoPos.Y + (ufoTex.Height / 2);

        //check if midpoint is inside each asteroid 
        for (int i = 0; i < numberOfAsteroids; i++)
        {
            if (x > asteroid[i].X && x < asteroid[i].X + asteroidTex.Width)
            {
                if (y > asteroid[i].Y && y < asteroid[i].Y + asteroidTex.Height)
                {
                    gameState = 2;//game over

                }
            }
        }



        //update ufo
        KeyboardState key = Keyboard.GetState();
            
        ufoSpriteNum = 0;
        if (key.IsKeyDown(Keys.Left) && ufoPos.X > 0)
        {
            ufoPos.X -= 5;
            ufoSpriteNum = 1;
        }
        if (key.IsKeyDown(Keys.Right) && ufoPos.X < 800 - ufoWidth)
        {
            ufoPos.X += 5;
            ufoSpriteNum = 2;
        }
        if (key.IsKeyDown(Keys.Up) && ufoPos.Y > 0)
        {
            ufoPos.Y -= 5;
        }
        if (key.IsKeyDown(Keys.Down) && ufoPos.Y < 600 - ufoTex.Height)
        {
            ufoPos.Y += 5;
        }
    }

    public void UpdateGameOver(GameTime gameTime)
    {
        KeyboardState key = Keyboard.GetState();

        if (key.IsKeyDown(Keys.Enter))
        {
            resetGame();
        }
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);


        switch (gameState)
        {
            // Draw Menu
            case 0:
                spriteBatch.Begin();
                spriteBatch.DrawString(font, "Asteroid Field\nArrows to Move\nPress Space to Play ", 
                                        new Vector2(100, 10), Color.White);
                spriteBatch.End();
                break;


            // Draw Main Game
            case 1:

                spriteBatch.Begin();

                spriteBatch.Draw(ufoTex, ufoPos, 
                                  new Rectangle(ufoSpriteNum*ufoWidth , 0, 128, 128), Color.White);

                //draw all asteroids
                for (int i = 0; i < numberOfAsteroids; i++)
                {
                    spriteBatch.Draw(asteroidTex, asteroid[i], Color.White);
                }

                spriteBatch.DrawString(font, "Score: " + score, new Vector2(20, 10), Color.White);

                spriteBatch.End();
                break;



            // Draw END OF GAME
            case 2:

                spriteBatch.Begin();

                spriteBatch.DrawString(font, "Asteroid Field\nFinal Score: " 
                                         + score, new Vector2(100, 10), Color.White);
                spriteBatch.DrawString(font, "Press Enter to Continue ", 
                                          new Vector2(100, 60), Color.White);
                spriteBatch.End();
                break;
        }
        base.Draw(gameTime);
    }
}