Parallax Scrolling: A Simple, Effective Way to Add Depth to a 2D Game
Parallax scrolling is a simple and effective way to create the illusion of depth in a 2D game. Whether you’re developing a vertical shooter or a horizontal side scrolling platformer, parallax scrolling is a tried and true staple of gaming that will greatly increase the immersion and graphical impact of your project.
In this tutorial, I'll cover the fundamentals of parallax scrolling, along with several methods of implementation, in such a way that you'll be able to confidently and successfully introduce parallax scrolling into your skill set, regardless of your current skill level.
Try the demo below to see scenes that use horizontal, vertical, both, and no parallax scrolling. Click the demo to activate it, then use the number keys to switch scenes and the arrow keys to move the spaceship (for the appropriate scenes).
What is Parallax Scrolling?
Parallax is defined as the apparent displacement of an observed object due to a change in the position of the observer. With 2D parallax scrolling, the observer’s position only changes along the x- and y-axes. Only an object’s speed and location will change with the position of the observer, as scaling the object would require a change along the z-axis.
Takashi Nishiyama’s Moon Patrol is widely credited as the first game to feature 2D parallax scrolling, but the technique existed in traditional animation as early as 1933. Using a multiplane camera, animators were able to create a non-stereoscopic 3D effect that created the illusion of depth by allowing different art assets to move at different speeds in relation to the perceived distance from the camera lens. This is how parallax scrolling is achieved in modern video games, but instead of a multiplane camera, scenes are assembled with multiple layers and a single game camera or view.
By dividing the background and foreground elements of a game into different layers, it is possible to control the speed and position of these elements based on their layers. The observer, in this case, is the player, and the game camera stays focused on a particular point or object, while the background and foreground layers move accordingly.
This focal point moves at ‘normal’ speed, or the speed defined by gameplay. Background objects move slower than the focal point while foreground objects move faster than the focal point. This results in an illusion of depth that makes a 2D scene feel more immersive.
Example 1: Horizontal Parallax Scrolling
In our first example, we have a very simple scene of a street at night that features horizontal scrolling with no interactive elements. The various background layers move at pre-determined speeds along the x-axis. For now, let’s focus on the basics of parallax scrolling without worrying about any player movement or shifting views.
First, let’s break down the individual elements and attributes of our scene. The game window is 600x300px, and our art assets each have a width of at least 600px. By using background elements that are larger than the game window, we can prevent the entire asset from being visible at any given time. Since the layers are tiled, this will help to prevent too much obvious repetition as the same asset scrolls indefinitely.
Our scene is composed of four layers. In this example, the number of the layer defines the order in which the asset is drawn to the screen as well as its movement speed. If this were a side-scrolling platformer, then our player object would exist on top of Layer 3. This layer would be the focal point of the observer, and would also dictate the speed of the background and foreground layers.
Layer 2 moves more slowly than Layer 3, and Layer 1 moves more slowly than Layer 2. Layer 4 exists as the foreground layer, so it moves more quickly than the focal point on Layer 3.
There are several ways you can implement this kind of
parallax scrolling technique. In this example, the layers move at
pre-determined speeds without referencing one another. If you plan on having
multiple scenes with varying quantities of background and foreground layers,
then it would be best to define layer speeds by reading the current speed of
the focal point layer. For instance, if the focal point is Layer 3 and is
moving at a speed of
5, then each successive background layer would move at a
speed less than
5. Any foreground layers would move at a speed greater than
//Variables focal_point_speed = 5; layer_difference = 1; //Focal point layer layer3.hspeed = focal_point_speed; //Background layers layer2.hspeed = layer3.hspeed – layer_difference; layer1.hspeed = layer2.hspeed – layer_difference; //Foreground layers layer4.hspeed = layer3.hspeed + layer_difference; layer5.hspeed = layer4.hspeed + layer_difference;
Example 2: Vertical Parallax Scrolling
While parallax scrolling is most often used with horizontal backgrounds, it can also be used in vertical scenes, as in this space shooter example. There may be more efficient ways to create a star field, but parallax scrolling gets the job done.
The most important thing to take away from this vertical example is that parallax scrolling works in all four directions along the x-and y-axes. (We will see just how important this is in our third and final example.)
This scene features four background layers: a static black background and three collections of stars at different sizes. The static background does not move, and each successive layer of stars grows larger and moves faster, with the final layer of stars ultimately determining the vertical speed of the focal point, the player’s spaceship. This type of parallax scrolling allows us to simulate the depth of space while also simulating forward movement. The player’s ship never actually moves up the screen, but you still get a sensation of fast-paced space traveling.
Example 3: Horizontal and Vertical Parallax Scrolling While Following an Object
Now that we have a better understanding of what parallax scrolling is about, we can begin to construct a scene in which both horizontal and vertical scrolling are implemented, along with a game view that tracks the movement of a player controlled object.
In the demo at the top of the tutorial, this scene is split into two examples. The first version shows what the scene is like without any parallax scrolling. The second version features full vertical and horizontal parallax scrolling, and it really illustrates how parallax scrolling can add a great deal of immersion and depth to what was originally a very flat and lifeless scene.
The most important aspect of this example is player movement and the game view. Because our background is no longer locked into a pre-determined speed or screen position, we have to calculate each layer’s speed and position in relation to the view window as the player moves around.
The origin of our view window is in the upper left corner at
(X,Y). Each background layer asset’s origin is in the upper left corner of the sprite at
(0,0). By finding the current x- and y-coordinates of the view window in relation to the game world, we can perform a calculation to determine where a background layer’s origin should be placed in the scene. This position changes as the view window moves around based on this calculation.
By using different values in the calculation of each layer, we are able to move each layer at different speeds, depending on how fast the player is moving.
The code to draw the layer that lies directly behind our player object is in the following format:
draw_background_tiled_horizontal(layer, x, y) where
draw_background_tiled_horizontal() is a simple function to draw a tiled asset at a specific location, and
bg_ex_3_2 is our layer asset.
//Layer 3 draw_background_tiled_horizontal( bg_ex_3_2, view_xview[view_current] / 2.5, (view_yview[view_current] / 10) + 300 );
The X value of the layer in this case is defined by the X value of the current view divided by a value of
2.5, creating a horizontal movement that moves slightly slower than the movement of the view itself.
Similarly, the Y value of the layer is defined by the Y value of the current view divided by
10. The Y value of the layer is then increased by
300 to position it correctly in relation to the game world. Without this extra addition of
300, the asset would appear near the top of the game world instead of near the bottom where we want it to be.
These values will obviously differ in your project, but the important thing to remember is that the speed of the layer’s movement will increase as the division number increases, but only up to a certain point. By using division, the layer can only move at the same speed or slower than the speed of the player.
The two layers behind this layer move more slowly, so the division numbers are smaller:
//Layer 1 draw_background_tiled_horizontal( bg_ex_3_0, view_xview[view_current] / 1.5, (view_yview[view_current] / 2.5) + 175 ); //Layer 2 draw_background_tiled_horizontal( bg_ex_3_1, view_xview[view_current] / 2, (view_yview[view_current] / 5) +250 );
To make a layer that moves faster than the focal point, such as a foreground layer, a slight change needs to be made. There is no foreground layer in this example, and the focal point layer is actually only visible at the bottom of the screen. The player is able to fly up and above the focal point, which is the ground, so the ship itself becomes the focal point. We refer to the ground as the focal point in this example because the ground is the only layer that moves at the same perceived speed as the spaceship. This is where we get our true sense of speed in the scene.
The ground layer moves more quickly than the view itself, so the code to draw this layer is slightly different than the other background layers:
//Focal point layer (ground) draw_background_tiled_horizontal( bg_ex_3_3, -view_xview[view_current] * 1.5, -view_yview[view_current] + 700 );
With layers that move more quickly than the view, we take the negative X and Y values of the current view and multiply them by some value. There is no division involved in calculating the speed of foreground layers. In this example, the ground layer moves at a horizontal speed that is one and a half times faster than the speed of the view window. No multiplication is performed on the vertical speed of the layer, so it moves at the same speed as the view. An additional value of
700 is added to the layer’s Y value to place it in the desired location near the bottom of the game world.
Parallax scrolling is a simple but very effective way to add the illusion of depth to a 2D game. I hope the examples in the demo have proven how effective it can be, and I hope the tutorial itself has proven how simple it is to implement!