Scrolling a 2D Background

This tutorial demonstrates creating a scrolling background using the XNA framework

Scrolling a 2D Background

Scrolling background images horizontally across the screen

 

If you're working on 2D games, at some point you're going to want to know how to create a scrolling background. This tutorial will cover setting up a horizontally scrolling background that auto-scrolls behind your character. Let's go ahead and get started.

 

Creating the new game project:

We are going to be using the "Sprite" class we created in the tutorial "Creating a 2D Sprite". Instead of creating a new XNA Game project, you can just download the source for that project and begin working from that game project.

If you would rather create a new game project to start from, but are having trouble remembering how to do that, just follow the steps in this tutorial here and come back to the this tutorial after you've refreshed your memory. Once you have your new game project, you will need to add the "Sprite" class created in this tutorial here to your new project.

Adding the images:

Now, let's add the background images that we are going to be using in this tutorial to the game project. You can download the images used in the project from here. Once you have downloaded the images, add all five background images to the Content folder in your game. If you are having trouble remembering how to add images to an XNA Game project, just follow the steps in this tutorial here and come back to this tutorial after you've refreshed your memory.

Enhancing the Sprite class:

To start out, we are going to make some enhancements to the Sprite class. These enhancements will make the sprite class a bit more flexible and allow us to more easily add in our scrolling background.

Add the following objects to the top of the Sprite class.

        //The size of the Sprite
        public Rectangle Size;
 
        //Used to size the Sprite up or down from the original image
        public float Scale = 1.0f;

The Size object will be used to store the height and width of the scaled sprite and the Scale object will be used to increase or decrease the size of the sprite from the original image. We are defaulting the Scale variable to 1.0 which tells the SpriteBatch to leave the image at its original size. Making Scale a larger number will increase the size of the sprite and a smaller number for scale will being to shrink the sprite.

Next, we will modify the LoadContent method to calculate and initialize the size of our Sprite. Modify the LoadContent method of the Sprite class to look like this.

        //Load the texture for the sprite using the Content Pipeline
        public void LoadContent(ContentManager theContentManager, string theAssetName)
        {
            mSpriteTexture = theContentManager.Load<Texture2D>(theAssetName);
            Size = new Rectangle(0, 0, (int)(mSpriteTexture.Width * Scale), (int)(mSpriteTexture.Height * Scale));
        }

Next, we want to use one of the many overrides of the SpriteBatch object to draw our image with our new Scale applied. Change the Draw method to look like the following.

        //Draw the sprite to the screen
        public void Draw(SpriteBatch theSpriteBatch)
        {
            theSpriteBatch.Draw(mSpriteTexture, Position, 
                new Rectangle(0, 0, mSpriteTexture.Width, mSpriteTexture.Height),Color.White, 
                0.0f, Vector2.Zero, Scale, SpriteEffects.None, 0);
        }

We have added a whole lot of parameters to pass into the Draw method of the SpriteBatch, but the one we are tracking is “Scale”. This will tell the SpriteBatch object to increase or decrease the size of the sprite proportionally.

Do a quick build now to make sure everything compiles. If you’re working off the source code for “Creating a 2D Sprite”, you should see the two sprites drawn to the screen.

Ok, now that we have laid the groundwork in our Sprite class we can now get started on adding the scrolling backgrounds to our game project.

We’ll start by adding some new Sprite objects to the top of the Game1.cs class. Add the following objects to the top of the class.

        Sprite mBackgroundOne;
        Sprite mBackgroundTwo;
        Sprite mBackgroundThree;
        Sprite mBackgroundFour;
        Sprite mBackgroundFive;

These Sprite objects will be used to move our background images across the screen.

Next, let’s Initialize our new Sprite objects and give them there scale value. The original size of the background images is 400 by 300 and the default size for a new Windows game is 800 by 600. So, if we double the size of our images, one will fill the whole screen. We can do that by adjusting the Scale value of our sprites.

Modify the Initialize method to look like this.

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            mSprite = new Sprite();
            mSpriteTwo = new Sprite();
 
            mBackgroundOne = new Sprite();
            mBackgroundOne.Scale = 2.0f;
 
            mBackgroundTwo = new Sprite();
            mBackgroundTwo.Scale = 2.0f;
 
            mBackgroundThree = new Sprite();
            mBackgroundThree.Scale = 2.0f;
 
            mBackgroundFour = new Sprite();
            mBackgroundFour.Scale = 2.0f;
 
            mBackgroundFive = new Sprite();
            mBackgroundFive.Scale = 2.0f;
 
            base.Initialize();
        }

You can see we have created a new instance of each of our Sprite objects and adjusted the Scale for our background images.

Now that we have initialized our sprites, we need to load the content. Modify the LoadContent method to look like this.

        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
            mSprite.LoadContent(this.Content, "SquareGuy");
            mSprite.Position = new Vector2(125, 245);
 
            mSpriteTwo.LoadContent(this.Content, "SquareGuy");
            mSpriteTwo.Position.X = 300;
            mSpriteTwo.Position.Y = 300;
 
            mBackgroundOne.LoadContent(this.Content, "Background01");
            mBackgroundOne.Position = new Vector2(0, 0);
 
            mBackgroundTwo.LoadContent(this.Content, "Background02");
            mBackgroundTwo.Position = new Vector2(mBackgroundOne.Position.X + mBackgroundOne.Size.Width, 0);
 
            mBackgroundThree.LoadContent(this.Content, "Background03");
            mBackgroundThree.Position = new Vector2(mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width, 0);
 
            mBackgroundFour.LoadContent(this.Content, "Background04");
            mBackgroundFour.Position = new Vector2(mBackgroundThree.Position.X + mBackgroundThree.Size.Width, 0);
 
            mBackgroundFive.LoadContent(this.Content, "Background05");
            mBackgroundFive.Position = new Vector2(mBackgroundFour.Position.X + mBackgroundFour.Size.Width, 0);
 
        }

You can see that we load the content for each of the Sprite images we added for our backgrounds. We then position each of the images in a trail from left to right. The first image starts at 0,0 which is the top left corner of the screen and then each image is placed in a line after that.

Scrolling backgrounds work by moving the background images across the screen in a snake like fashion. When an image moves all the way off the screen on the left, it is placed at the end of the snake tail so that the images can continually loop in that fashion giving you a seamless horizontally scrolling background.

To create this effect, we need to both move the images and then check to see if the image has moved off the screen and re-position it at the end. We do that by modifying the Update method to look like this.

        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 (mBackgroundOne.Position.X < -mBackgroundOne.Size.Width)
            {
                mBackgroundOne.Position.X = mBackgroundFive.Position.X + mBackgroundFive.Size.Width;
            }
 
            if (mBackgroundTwo.Position.X < -mBackgroundTwo.Size.Width)
            {
                mBackgroundTwo.Position.X = mBackgroundOne.Position.X + mBackgroundOne.Size.Width;
            }
 
            if (mBackgroundThree.Position.X < -mBackgroundThree.Size.Width)
            {
                mBackgroundThree.Position.X = mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width;
            }
 
            if (mBackgroundFour.Position.X < -mBackgroundFour.Size.Width)
            {
                mBackgroundFour.Position.X = mBackgroundThree.Position.X + mBackgroundThree.Size.Width;
            }
 
            if (mBackgroundFive.Position.X < -mBackgroundFive.Size.Width)
            {
                mBackgroundFive.Position.X = mBackgroundFour.Position.X + mBackgroundFour.Size.Width;
            }
            
            Vector2 aDirection = new Vector2(-1, 0);
            Vector2 aSpeed = new Vector2(160, 0);
 
            mBackgroundOne.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundTwo.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundThree.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundFour.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundFive.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;            
 
            base.Update(gameTime);
        }

This code consists of two different sections. We’ll discuss the first section of code below which deals with keeping the "chain" of images going.

            if (mBackgroundOne.Position.X < -mBackgroundOne.Size.Width)
            {
                mBackgroundOne.Position.X = mBackgroundFive.Position.X + mBackgroundFive.Size.Width;
            }
 
            if (mBackgroundTwo.Position.X < -mBackgroundTwo.Size.Width)
            {
                mBackgroundTwo.Position.X = mBackgroundOne.Position.X + mBackgroundOne.Size.Width;
            }
 
            if (mBackgroundThree.Position.X < -mBackgroundThree.Size.Width)
            {
                mBackgroundThree.Position.X = mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width;
            }
 
            if (mBackgroundFour.Position.X < -mBackgroundFour.Size.Width)
            {
                mBackgroundFour.Position.X = mBackgroundThree.Position.X + mBackgroundThree.Size.Width;
            }
 
            if (mBackgroundFive.Position.X < -mBackgroundFive.Size.Width)
            {
                mBackgroundFive.Position.X = mBackgroundFour.Position.X + mBackgroundFour.Size.Width;
            }

You might expect to move the background images first, but this will actually begin to create gaps between the images. Often in game development, you have to be very aware in the order that you are doing things. If we move the images first, then check to see if they’ve moved off the screen, you have to remember that the player has never seen that happen yet because they haven’t been drawn to the screen yet! That doesn’t happen until Draw is called.

So, instead, we first move images that have moved off the screen (and hopefully the player has seen this occur already) to the end of the trail of images. This is done by checking the Sprite’s current position and seeing if it’s moved further then it’s width off the screen. This means that the entire image is now out of the viewable area for the player. If this is true, then we move the image to the one it should be following. The first image follows the fifth, and then the fifth follows the fourth and so on and so on.

Now let’s look at the second part of the code, the movement.

            Vector2 aDirection = new Vector2(-1, 0);
            Vector2 aSpeed = new Vector2(160, 0);
 
            mBackgroundOne.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundTwo.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundThree.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundFour.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
            mBackgroundFive.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;            

Movement is done by increasing the position of a sprite by multiplying Direction, times the speed, times the time that has elapsed.

Direction is just a -1 or 1 in the X and or Y direction. In our case, we want to move the sprites to the left, so we are decreasing in the X direction, so we use a negative one. We are not moving at all in the Y direction, so we leave that 0 for our Direction vector.

Speed is how fast you want the sprite to move. We want the Sprite to move at a decent pace in the X direction and not at all for Y. You can increase or decrease the speed of the scrolling by increasing or decreasing this number.

Finally, you multiply by time elapsed. This is done so that computers that are faster and with faster refresh rates see the same speed of scrolling that slower computers with slower refresh rates see. By default, the XNA framework tries to maintain this internally by keeping everything moving at a fixed time step, but it’s a good habit to get into.

Ok, we’re re-positioning our background sprites as necessary and moving them along at a steady clip in the right direction. The only thing left to do it draw them to the screen.

Modify the Draw method to look like this.

        protected override void Draw(GameTime gameTime)
        {
            graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
 
            // TODO: Add your drawing code here
            spriteBatch.Begin();
 
            mBackgroundOne.Draw(this.spriteBatch);
            mBackgroundTwo.Draw(this.spriteBatch);
            mBackgroundThree.Draw(this.spriteBatch);
            mBackgroundFour.Draw(this.spriteBatch);
            mBackgroundFive.Draw(this.spriteBatch);
 
            mSprite.Draw(this.spriteBatch);
            mSpriteTwo.Draw(this.spriteBatch);
            spriteBatch.End();
 
            base.Draw(gameTime);
        }

The important thing to note here is that we are drawing the backgrounds BEFORE the two square guy sprites. Sprites are drawn in layers with the first Draw calls drawn first to the screen and the others drawn on top of them. It’s important to remember that when adding your draw code. If we had placed the backgrounds after the sprites, we would have never seen them because the background images would have been drawn on top of the square guys.

That’s it, go ahead and Build CropperCapture2632 the game. You should see the background images begin to scroll horizontally across the screen and the two square guys looking like their floating through the air.

Scrolling Background

Congratulations! You now have successfully learned how to add a horizontally scrolling background to your game. While, this is a good introductory example to scrolling a Horizontal background, but the code wasn’t written in a very object oriented way. I have taken this tutorial a bit further and done some work to make it a little more re-usable project. You can check out the more advanced Horizontal scrolling example.

Can you think of some things you can change? How hard would it be to make this scroll vertically? Do you think you know what you might change?

Play with it, experiment and ask questions. Most of all make sure you’re having fun!

Technorati Tags: