Sprite Sheets in XNA: Keyboard Movement

July 17, 2008

You may want to start from my previous article, Sprite Sheet Basics before beginning here!

Previously we explored the basics of animating a sprite sheet in XNA, but we only allowed the Sprite Sheet to do literally that, animate. Here we will begin to put our new skills into use by allowing our user to move our sprites in one of four directions (North, South, East, West).

Before we just jump in and start making our character fly around I feel we need to begin by creating a Sprite Sheet class. If you don’t know much about classes or object oriented programming (OOP) in general then I suggest you read up. Maybe check out here for an introduction to creating classes in C#. If people really need help I could write a tutorial on it, but I don’t plan on it without requests.

So, to start we’ll grab the variables we had defining our Sprite Sheet in the last tutorial and plug them into our newly created class called “SpriteSheet“.

Texture2D m_texture;
float m_timer = 0f;
float m_interval = 1000f / 10f;
int m_currentFrame = 7;
int m_spriteWidth = 25;
int m_spriteHeight = 35;
Rectangle m_sourceRect;

I’m using the same sprite sheet as last time (albeit Goku this time!) so that variable values are the same. I’ve also prefixed each variable with m_ which tells me the variable is a member variable of the SpriteSheet class.

Next I need to create the constructor which is called when an object is instantiated from a class (Am i talking crap? Get researching on OOP!). Let’s have a think what parameters a user might need to supply to the class in order for it to work.

  • I’m thinking we’re definitely going to need to be supplied with the texture
  • We might also want to supply the frame to start on depending on if we want the Sprite facing towards us or left etc.
  • We’ll also definitely need to the width and height of a single frame on the texture

So we can now create our constructor with these things in mind:

public SpriteSheet(Texture2D texture, int currentFrame,int spriteWidth,int spriteHeight)
        {
            m_texture = texture;
            m_spriteWidth = spriteWidth;
            m_spriteHeight = spriteHeight;
            m_currentFrame = currentFrame;
        }

We have also set the member variables of our class equal to the parameters supplied by the user.

Now we can have a think about the real challenge, making our character walk in the right direction when the keyboard is pressed! Let’s have a think about what we might need to do:

  • Get the current keyboard state (check if a button has been pressed)
  • Check if more than one button has been pressed (we only want the character to move in four directions) and return if there has
  • According to which key has been pressed (Left, Right, Up, Down) move the character appropriately in that direction and animate the walking in that direction
  • If the character has stopped moving make sure it stops on one of the standing frames and not a stepping frame

Inside this keyboard checking function I spy another function, which is animating the walking. We’re going to do this using four different functions, each for a direction. Let’s have a think about what these functions might need:

  • First we need to do a jump straight to the correct frame for the direction. This prevents the sprite doing weird rotations on a complete direction change like South to West. We should do this by keeping track of whether the key being pressed has been changed.
  • Increase the trusty timer
  • If the timer is greater than the interval (100 ms) then do the following:
    • Increase the current frame
    • Check to see if the frame we’re on is outside of the frames for this direction (Each direction consists of three frames for my sheet, Standing, Left foot forward, Right foot forward). If we are go back to the first frame for the direction
    • Reset the timer

So we’re going to have a lot of IF’s in this! To start I’ll point out that these functions do require a single parameter, gameTime. We need this to implement the timer since it keep time according to the speed at which the game calls the Update function which is independent of our class. Let’s set up two more variables to store our keyboard state:

KeyboardState m_currentState;
KeyboardState m_previousState;

Now to throw in our KeyboardMove function:

public void keyBoardMove(GameTime gameTime)
   {
        //Keyboard States
        m_previousState = m_currentState;
        m_currentState = Keyboard.GetState();
 
        //Check only one key is pressed, if more than one is pressed, return from the function
        if (m_currentState.GetPressedKeys().Length > 1)
          {
             return;
          }
 
        //Check if right key is pressed, it if is make the animation call
        //and move the sprite 5 pixels in the positive X direction
         if (m_currentState.IsKeyDown(Keys.Right))
          {
              animateRight(gameTime);
              m_position.X += 5;
          }
 
        //Ditto previous but left and 5 pixels in the negative X
         if (m_currentState.IsKeyDown(Keys.Left))
          {
              animateLeft(gameTime);
              m_position.X -= 5;
          }
 
        //Ditto previous but Up and 5 pixels in the negative Y
         if (m_currentState.IsKeyDown(Keys.Up))
          {
              animateUp(gameTime);
              m_position.Y -= 5;
          }
 
        //Ditto previous but down and 5 pixels in the positive Y
         if (m_currentState.IsKeyDown(Keys.Down))
          {
              animateDown(gameTime);
              m_position.Y += 5;
          }
 
        //Check if no keys are pressed, if they aren't reset the frame to
        //the standing frame of each direction
         if (m_currentState.GetPressedKeys().Length == 0)
          {
             if (m_currentFrame >= 0 && m_currentFrame <= 2)
                {
                    m_currentFrame = 1;
                }
             if (m_currentFrame >= 3 && m_currentFrame <= 5)
                {
                    m_currentFrame = 4;
                }
             if (m_currentFrame >= 6 && m_currentFrame <= 8)
                {
                    m_currentFrame = 7;
                }
             if (m_currentFrame >= 9 && m_currentFrame <= 11)
                {
                    m_currentFrame = 10;
                }
          }
 
//Set the rectangle for drawing
m_sourceRect = new Rectangle(m_currentFrame * m_spriteWidth, 0, m_spriteWidth, m_spriteHeight);
 
//Set the origin up
m_origin = new Vector2(m_sourceRect.Width / 2, m_sourceRect.Height / 2);
 
 }

Notice the values I’m using for my frames there will change if don’t have your setup exactly the same as mine, as will your values for the next function:

private void animateRight(GameTime gameTime)
 {
      //Check if the keyboard state is a new one, if it is snap straight to the standing
      //frame for the direction. Allows quick turning
      if (m_currentState != m_previousState)
        {
            m_currentFrame = 4;
        }
 
      //Incremement timer using paramater
      m_timer += (float)gameTime.ElapsedGameTime.TotalMilliseconds;
 
      //Check if timer is greater than interval
      if (m_timer > m_interval)
        {
            //If is incrememnt current frame
            m_currentFrame++;
 
            //Check frame is within direction frames, if not set back to standing
            if (m_currentFrame > 5)
             {
                 m_currentFrame = 4;
             }
 
            //Reset timer
            m_timer = 0f;
           }
}

I’m only showing the animation function for right because the others are identical except for using different frames. If you have a keen eye for detail you will notice I used frame 4 for ‘standing’ when if you count the frames it is clearly frame 5. However, we start from 0 as usual in C# due to the first frame needing a source rectangle starting from 0!

If you check the source I have added some properties to grab the texture and such and also added origin and position variables.

That’s about all folks, have any questions? Just ask!


Source is Here

Please note that the source is compiled for windows, and is also compiled for XNA 4.0! You will also need Visual Studio 2010

Also note if thats your Goku sprite just tell me for thanks or removal!

7 Responses to “Sprite Sheets in XNA: Keyboard Movement”

  1. Hey mate i was just wandering how to get a diagonal moving sprite.

  2. OK, this is very useful, but I’m using a tutorial from xnadevelopment.com. The first tutorials are about getting a sprite to move, duck, jump and shoot fireballs. yay! except that I only need 4 possible animations to show, walk Left/Right and duck Left/Right. If it makes any difference, just like in the tutorial I mentioned above, my Wizard class inherits from my Sprite class.
    any help would be much appreciated!

  3. how do i call on the class in my game1.cs then ? to load the sprite sheet , i have cancelled out all the coding that made the sprite loop and i had cancelled previous coding i had completed to make a sprite move around using the keyboard but not animated

  4. I’m not sure what you mean Damian? Email me about it!

  5. I did it like this:
    (so far the sprite can only move up or down)
    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
    if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Down))
    {
    float y = playerPosition.Y;
    float x = playerPosition.X;
    playerPosition = new Vector2(x, y + 2);
    }

    if (Keyboard.GetState(PlayerIndex.One).IsKeyDown(Keys.Up))
    {
    float y = playerPosition.Y;
    float x = playerPosition.X;
    playerPosition = new Vector2(x, y – 2);
    }

    base.Update(gameTime);
    }

  6. Would love to see updated tutorials on your site…

  7. I’d like to personally thank you for making tutorials that are actual good. It’s way harder than it should be to find a tutorial on the internet simple enough for a beginner like me to follow, and one that explains everything clearly.

Leave a Reply