Push Button, Receive Code

Programming tutorials, games, music...free beer.

Diagonally Scrolling Backgrounds

Posted by Mark on Monday July 28th, 2014 at 6:00am

Most people who have made even the simplest of games understand how to make a scrolling background. If not, there are many tutorials out there explaining how it is done. However, I have not encountered any on the net that describe how to do a diagonal scrolling background. In this tutorial, I'll show you how to do just that. The first step is to make a background that is seamlessly repeatable. I snagged my background from subtlepatterns.com. First thing is first, let's set up the graphics for it:

...

    sf::VideoMode mode = sf::VideoMode::getDesktopMode();
    float scaleX = mode.width/800.f;
    float scaleY = mode.height/600.f;
...
    sf::Texture tex;
    if(!tex.loadFromFile("img/star.png"))
    {
        std::cerr<<"Could not load star.png"<<std::endl;
    }

    //set up the parallax diagonal scrolling images
    m_bgOne.setTexture(tex);
    m_bgTwo.setTexture(tex);
    m_bgThree.setTexture(tex);
    m_bgFour.setTexture(tex);
    m_bgOne.setOrigin(0.f,0.f);
    m_bgTwo.setOrigin(0.f,0.f);
    m_bgThree.setOrigin(0.f,0.f);
    m_bgFour.setOrigin(0.f,0.f);
    m_bgOne.setScale(scaleX,scaleY);
    m_bgTwo.setScale(scaleX,scaleY);
    m_bgThree.setScale(scaleX,scaleY);
    m_bgFour.setScale(scaleX,scaleY);
    float w = m_bgOne.getGlobalBounds().width;
    float h = m_bgOne.getGlobalBounds().height;
    m_bgOne.setPosition(0.f,0.f);
    m_bgTwo.setPosition(w,-h);
    m_bgThree.setPosition(0.f,-h);
    m_bgFour.setPosition(w,0.f);
...    

As you can see, you just need four sprites based on the one texture. Make sure the origins for each sprite are set to 0.f,0.f. After that, you will set them up in a grid with one at 0.f,0.f, another above it (0.f, -h), another one above and to the right (w, -h), and finally another one to the right (w,0.f).

On a side note, I used a scaling factor based on an 800 pixel wide by 600 pixel high screen - so if the screen resolution is set to 1768 pixels by 992 pixels (my screen resolution, for example), the scaling factor would be about 1.78 for width (scaleX) and 1.65 for height (scaleY). I used this to scale the width and height of each sprite according to the resolution of the user's screen. You can do this by grabbing the video mode with SFML (sf::VideoMode::getDesktopMode();) and dividing it by whatever you want your baseline to be. I chose 800 by 600 as the base resolution because it is reasonable for desktop apps. However, with support for mobile devices coming to SFML in the future, you may have to scale at a much smaller baseline or find another solution if it does not look good.

Next, we'll need to control the motion of the grid so that it moves diagonally:

...
            if(m_bgOne.getPosition().y >= h && m_bgOne.getPosition().x <= 0.f)
            {
                m_bgOne.setPosition(w,-h);
            }
            else
                m_bgOne.move(-30.f*scaleX*TimePerFrame.asSeconds(), 30.f*scaleY*TimePerFrame.asSeconds());

            if(m_bgTwo.getPosition().y >= h && m_bgTwo.getPosition().x <= 0.f)
            {
                m_bgTwo.setPosition(w,-h);
            }
            else
                m_bgTwo.move(-30.f*scaleX*TimePerFrame.asSeconds(), 30.f*scaleY*TimePerFrame.asSeconds());

            if(m_bgThree.getPosition().y >= 0)
            {
                m_bgThree.setPosition(0.f,-h);
            }
            else
                m_bgThree.move(-30.f*scaleX*TimePerFrame.asSeconds(), 30.f*scaleY*TimePerFrame.asSeconds());

            if(m_bgFour.getPosition().y >= h)
            {
                m_bgFour.setPosition(w,0.f);
            }
            else
                m_bgFour.move(-30.f*scaleX*TimePerFrame.asSeconds(), 30.f*scaleY*TimePerFrame.asSeconds());
...

So, you just simply move each sprite down and to the left in this case, and when m_bgOne or m_bgTwo (the first and second copies of the texture), leave the screen, their positions are reset to the top-right quadrant (w,-h). The other two, m_bgThree and m_bgFour, are reset to the top-left (0.f,w) and bottom-right (w,h). These two sprites are really what tie the effect together. The other two (m_bgOne and m_bgTwo) are similar to a horizontal or vertical scrolling background, in that they essentially behave in the same manner.

For good practice, you should tie your motion to a clock (or preferably a fixed time step), a scaling factor for different screen sizes, and a value at which you would like to set the speed (I chose 30.f, but it depends on what you are trying to achieve, visually). Remember that although scaling the motion of these objects is not critical in this use case, you will want to for other things such as particles and projectiles. You must remember Rate = Distance*Time. If you develop with a fixed speed for multiple screen sizes then that is what you will get - and it may not be the type of behavior you would expect. For example, projectiles may seem sluggish on larger screens or super fast on smaller screens. You probably want to scale it accordingly.

This produces a repeating and seamless diagonal scrolling background. Make sure you remember to draw the sprites, or it's all for nothing. ;)

Enjoy!