In this tutorial, we will see the tricks and the code required to achieve a parallax scrolling background effect. The parallax effect is when different layers of backgrounds are moved at different speeds to achieve the effect of motion and depth. By moving the front layer(s) faster than the back the distance/depth effect is achieved. Video games didn’t invent this technique and the first modern use of the parallax effect dates back to early cinema. The famous Disney production Snow White used this effect as well as another trick where layers of backgrounds are moved in opposite directions to achieve a rotating effect.

The first time the effect was used in a video Game was Atari’s Moon Patrol. Why not take a look at the video in the previous link. Notice the foreground which is plain green with the occasional pot-hole, scrolls at a different(faster) speed to the background hills. It is also possible with more modern hardware (like our Android phones) to have transparent parts to the layers and overlap them with other layers to create a more pleasing effect. Let’s code a parallax scrolling background.

  • The courses above are up to 95% off - only $19 using voucher code UDEMARCH. Limited time offer.


About this project

Skill level 1
Time to complete 1 hour

New Concepts:

  1. Creating a multi-layered parallax effect
  2. Integrating the prallax feature with a simple game engine

Recommended preparation tutorials

How the parallax affect is achieved in code

The first frame of the game shows the background image like this. Please note these images are not the ones to add into your project. They are shown later in the tutorial.

parallax_explanation_part1

The way the next frame is shown is to move the image off-screen to the left. So what do we show on the last pixel on the right-hand side of the screen? We will make a reversed copy of the same image and show it to the right of the original(unreversed) image.

parallax_explanation_part2

As the original image and the reversed image are steadily scrolled to the left, eventually, half of each image will be shown and so on.

parallax_explanation_part3

Eventually, we will be reaching the end of the original image and the last pixel on the right-hand-side of the reversed image will eventually be on-screen.

parallax_explanation_part4

At the point when the reversed image is shown in full on the screen, just like the original image was at the start, we will move the original image over to the right-hand side. The two backgrounds will continuously scroll and as the right-hand image (either original or reversed) becomes the entire view that the player sees, the left-hand image (either original or reversed) will be moved to the right-hand-side ready to be scrolled into view.

Let’s start coding.

Starting the project

Start a new project in Android Studio and choose the Empty Activity template without a layout file because we don’t need loads of auto-generated code and files. All the code and images are available on this page but if you want to help me out by telling others about this page then take a look at my bonus download for this project.

Making the game full-screen landscape

We want to use every pixel that the device has to offer so we will make changes to the app’s AndroidManifest.xml configuration file.

  1. In the project explorer pane in Android Studio double click on the manifests folder, this will open up the AndroidManifest.xml file in the code editor.
  2. In the AndroidManifest.xml file, locate the following line of code,  android:name=".ParallaxActivity">
  3. Place the cursor before the closing > shown above. Tap the enter key a couple of times to move the > a couple of lines below the rest of the line shown above.
  4. Immediately below ParallaxActivity but BEFORE the newly positioned > type or copy and paste these two lines to make the game run full screen and lock it in the landscape orientation.
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape"

The code structure

The code structure for this game is almost the same as the Simple Game Engine tutorial with one extra class and one extra method in the main View-based class. We will call the Activity class ParallaxActivity and the View-based class ParallaxView. ParallaxActivity will set up ParallaxView in onCreate and then set it as the view for the app.  ParallaxView will hold a Thread instance that will run the main game loop which in turn will consist of the usual calls to update and draw methods. We won’t obscure the parallax code by adding any extra game objects so the update method will only update the positions of our multiple backgrounds and the draw method (big reveal!) will draw them.

The class that does all the hard work will be called Background. The Background class will have a fairly in-depth constructor to initialize the instance, a method called update to control shifting the two images (regular and reversed) of the background around. This implies that each background will be a separate instance of the Background class. ParallaxView will hold these in an ArrayList called backgrounds. A  ArrayList for just two is probably overkill but you can then add as many layers as you like.

The draw method will just need to call the layers in order at the same time as inserting any game objects in between the appropriate layers. We will simply draw some text in between our layers just to see the effect.

Coding the Parallax Activity

Add the following code for the ParallaxActivity class. All it does is instantiate an instance of ParallaxView, pass in some resolution information and set ParallaxView as the view for the game. If anything is unclear about any of the code that isn’t specifically about the parallax background, you can find more detail in the Simple Game Engine tutorial.

import android.app.Activity;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;

public class ParallaxActivity extends Activity {

    // Our object to handle the View
    private ParallaxView parallaxView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get a Display object to access screen details
        Display display = getWindowManager().getDefaultDisplay();

        // Load the resolution into a Point object
        Point resolution = new Point();
        display.getSize(resolution);

        // And finally set the view for our game
        parallaxView = new ParallaxView(this, resolution.x, resolution.y);

        // Make our parallaxView the view for the Activity
        setContentView(parallaxView);

    }

    // If the Activity is paused make sure to pause our thread
    @Override
    protected void onPause() {
        super.onPause();
        parallaxView.pause();
    }

    // If the Activity is resumed make sure to resume our thread
    @Override
    protected void onResume() {
        super.onResume();
        parallaxView.resume();
    }
}

  • The courses above are up to 95% off - only $19 using voucher code UDEMARCH. Limited time offer.

Coding the ParallaxView class

Add a new class to the project called ParallaxView and add the following code. All this code does is set up the class and a simple game loop. Currently, we do nothing in the  update method and just draw a bit of text in the draw method. Take a look at the comments that indicate where we will add our parallax specific code once we have coded the Background class. If any of this code is unclear refer to the Simple Game Engine tutorial.

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.util.ArrayList;

public class ParallaxView extends SurfaceView implements Runnable {

    private volatile boolean running;
    private Thread gameThread = null;

    // For drawing
    private Paint paint;
    private Canvas canvas;
    private SurfaceHolder ourHolder;

    // Holds a reference to the Activity
    Context context;

    // Control the fps
    long fps =60;

    // Screen resolution
    int screenWidth;
    int screenHeight;

    ParallaxView(Context context, int screenWidth, int screenHeight) {
        super(context);

        this.context = context;

        this.screenWidth = screenWidth;
        this.screenHeight = screenHeight;

        // Initialize our drawing objects
        ourHolder = getHolder();
        paint = new Paint();

    }

    @Override
    public void run() {

        while (running) {
            long startFrameTime = System.currentTimeMillis();

            update();

            draw();

            // Calculate the fps this frame
            long timeThisFrame = System.currentTimeMillis() - startFrameTime;
            if (timeThisFrame >= 1) {
                fps = 1000 / timeThisFrame;
            }
        }
    }

    private void update() {
        // Update all the background positions

    }

    private void draw() {

        if (ourHolder.getSurface().isValid()) {
            //First we lock the area of memory we will be drawing to
            canvas = ourHolder.lockCanvas();

            //draw a background color
            canvas.drawColor(Color.argb(255, 0, 3, 70));

            // Draw the background parallax

            // Draw the rest of the game
            paint.setTextSize(60);
            paint.setColor(Color.argb(255, 255, 255, 255));
            canvas.drawText("I am a plane", 350, screenHeight / 100 * 5, paint);
            paint.setTextSize(220);
            canvas.drawText("I'm a train", 50, screenHeight / 100*80, paint);

            // Draw the foreground parallax

            // Unlock and draw the scene
            ourHolder.unlockCanvasAndPost(canvas);
        }
    }

    // Clean up our thread if the game is stopped
    public void pause() {
        running = false;
        try {
            gameThread.join();
        } catch (InterruptedException e) {
            // Error
        }
    }

    // Make a new thread and start it
    // Execution moves to our run method
    public void resume() {
        running = true;
        gameThread = new Thread(this);
        gameThread.start();
    }

}// End of ParallaxView

Coding the Background class

Now we get to see how we will implement the parallax scrolling background using the visual technique described at the start of the tutorial. The Background class we will now code will be instantiated once for each background image, the grass, and the city skyline.

Create a new class called Background and add this code which has all the member variables as well as the declaration of the constructor and update methods. Pay attention to the names and the types of the variables as we will use them soon when we actually code the two methods. Also take a look at the parameters of the methods, especially the constructor.

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;

public class Background {

    Bitmap bitmap;
    Bitmap bitmapReversed;

    int width;
    int height;
    boolean reversedFirst;
    float speed;

    int xClip;
    int startY;
    int endY;

    Background(Context context, int screenWidth, int screenHeight, String bitmapName,  int sY, int eY, float s){

    }

    public void update(long fps){

    }
}

Adding the parallax image resources

As the final preparation, add the two images below into the drawable folder in Android Studio.

This image will be the back layer and be positioned at coordinates 0,0 at the top left of the screen (to start with).

skyline

Next, we will draw some text at different heights as seen in the draw method we coded previously.

Finally, we will draw this image near the bottom of the screen as the third layer.

grass

Coding the Background class constructor

The constructor is where we get everything ready to call update each frame of the game.  Add and study the code then we can talk about it.

Background(Context context, int screenWidth, int screenHeight, String bitmapName,  int sY, int eY, float s){

	// Make a resource id out of the string of the file name
	int resID = context.getResources().getIdentifier(bitmapName,
			"drawable", context.getPackageName());

	// Load the bitmap using the id
	bitmap = BitmapFactory.decodeResource(context.getResources(), resID);

	// Which version of background (reversed or regular)
	// is currently drawn first (on left)
	reversedFirst = false;

	//Initialise animation variables.

	// Where to clip the bitmaps
	// Starting at the first pixel
	xClip = 0;

	//Position the background vertically
	startY = sY * (screenHeight / 100);
	endY = eY * (screenHeight / 100);
	speed = s;

	// Create the bitmap
	bitmap = Bitmap.createScaledBitmap(bitmap, screenWidth,
			(endY - startY)
			, true);

	// Save the width and height for later use
	width = bitmap.getWidth();
	height = bitmap.getHeight();

	//Create a mirror image of the background (horizontal flip)
	Matrix matrix = new Matrix();
	matrix.setScale(-1, 1);
	bitmapReversed = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

}

First, in the constructor, we use the chained getResources().getIdentifier() methods to make a resource id that refers to the bitmaps we just added to the drawable folder. The name of the file is contained in the bitmapName parameter and can, therefore, be different for each call to the constructor. Next, we initialize bitmap and set the Boolean reversedFirst to false. This will tell our code which image (regular or reversed) to draw on the left and which on the right. Next, we initialize xClip to . The xClip variable will hold the horizontal position at which to cut/clip the current background. It will be strategically manipulated in the update method of this class each frame. We set it to zero which means we don’t clip anything to start with, just as discussed at the start of the tutorial.

Here is some code repeated from above.

//Position the background vertically
startY = sY * (screenHeight / 100);
endY = eY * (screenHeight / 100);
speed = s;

This code uses the parameters sY, eY and s to initialize the member variables startY, endY and speed. What is more interesting is why we initialize startY and endY the way that we do. The reason is that we want our code to work on screens of all resolutions. By dividing screenHeight by 100 and multiplying it by the passed in parameters it means that when we call the constructor we can pass in a percentage vertical starting height rather than having to calculate the ideal height for any given screen resolution. The speed variable represents the number of pixels per second to move this particular background.

The final part of the code creates a bitmap and captures its size in the width and height variables. The Matrix class and the setScale method is what allows us to create a reversed copy of the image in the final line of code of the constructor.

Coding the Background update method

The update method is short and sweet because we have already setup everything we need. The first thing that happens is that xClip is modified based on the speed of the background and the current frame rate. The if/ else blocks check if we have reached the end of the current image and if we have switches the value of reversedFirst and resets xClip to either or width. We will see how these values are used in ParalaxView to draw the correct image (regular or reversed) in the correct position (first or second) with the appropriate amount of clipping on each. Add the update method and we are not far from being finished.

    public void update(long fps){

        // Move the clipping position and reverse if necessary
        xClip -= speed/fps;
        if (xClip >= width) {
            xClip = 0;
            reversedFirst = !reversedFirst;
        } else if (xClip <= 0) {
            xClip = width;
            reversedFirst = !reversedFirst;

        }
    }

Updating the ParallaxView class

First, declare an ArrayList to hold the type of Background called backgrounds as the first line of code below shows. Note that you only need to add the first line. The rest of the code we added previously.

public class ParallaxView extends SurfaceView implements Runnable {

    ArrayList<Background> backgrounds;

    private volatile boolean running;
    private Thread gameThread = null;

    // For drawing
    private Paint paint;
    private Canvas canvas;
    private SurfaceHolder ourHolder;

    // Holds a reference to the Activity
    Context context;

    // Control the fps
    long fps =60;

    // Screen resolution
    int screenWidth;
    int screenHeight;

Now, add this extra code in the ParallaxView constructor to initialize the ArrayList and populate it with two backgrounds using calls to the Background constructor we just coded. Note the arguments. The different starting and ending heights along with different image names and speeds.

ParallaxView(Context context, int screenWidth, int screenHeight) {
	super(context);

	this.context = context;

	this.screenWidth = screenWidth;
	this.screenHeight = screenHeight;

	// Initialize our drawing objects
	ourHolder = getHolder();
	paint = new Paint();

	// Initialize our array list
	backgrounds = new ArrayList<>();

	//load the background data into the Background objects and
	// place them in our GameObject arraylist

	backgrounds.add(new Background(
			this.context,
			screenWidth,
			screenHeight,
			"skyline",  0, 80, 50));

	backgrounds.add(new Background(
			this.context,
			screenWidth,
			screenHeight,
			"grass",  70, 110, 200));

	// Add more backgrounds here

}

As the code to draw a background is relatively long and we will use it multiple times we will make it into a method. This drawBackground method will be called from the draw method along with the position in the ArrayList of the background we want to draw. Take a close look at the code and the comments and then we can talk about it a bit.

private void drawBackground(int position) {

	// Make a copy of the relevant background
	Background bg = backgrounds.get(position);

	// define what portion of images to capture and
	// what coordinates of screen to draw them at

	// For the regular bitmap
	Rect fromRect1 = new Rect(0, 0, bg.width - bg.xClip, bg.height);
	Rect toRect1 = new Rect(bg.xClip, bg.startY, bg.width, bg.endY);

	// For the reversed background
	Rect fromRect2 = new Rect(bg.width - bg.xClip, 0, bg.width, bg.height);
	Rect toRect2 = new Rect(0, bg.startY, bg.xClip, bg.endY);

	//draw the two background bitmaps
	if (!bg.reversedFirst) {
		canvas.drawBitmap(bg.bitmap, fromRect1, toRect1, paint);
		canvas.drawBitmap(bg.bitmapReversed, fromRect2, toRect2, paint);
	} else {
		canvas.drawBitmap(bg.bitmap, fromRect2, toRect2, paint);
		canvas.drawBitmap(bg.bitmapReversed, fromRect1, toRect1, paint);
	}

}

The first thing the code does is make a reference to the current background. Actually, this unnecessarily slows the code down a little but  it makes it much more readable as we can refer to bg.width instead of backgrounds.get(position).width etc..

In the code, we create four RectF objects. These objects hold the coordinates from each of the images and the coordinates of the screen at which to draw them. All the values are taken from the background.

Finally, we draw the two images side by side using the four RectF objects to capture the appropriate part of each image and place it at the appropriate coordinates. The if/ else blocks use the reversedFirst Boolean to determine which image is currently drawn on the left or the right.

Updating and drawing the backgrounds

This code simply loops through any Background objects that are in the backgrounds array and calls their update method passing in the current frame rate as required. In the updated draw method, there are two calls to drawBackground, one before the text is drawn with the argument of zero and one after the text is drawn with one as the argument. This ensures the city skyline is drawn first, the text second and the bushes last.

private void update() {
	// Update all the background positions
	for (Background bg : backgrounds) {
		bg.update(fps);
	}

}

private void draw() {

	if (ourHolder.getSurface().isValid()) {
		//First we lock the area of memory we will be drawing to
		canvas = ourHolder.lockCanvas();

		//draw a background color
		canvas.drawColor(Color.argb(255, 0, 3, 70));

		// Draw the background parallax
		drawBackground(0);

		// Draw the rest of the game
		paint.setTextSize(60);
		paint.setColor(Color.argb(255, 255, 255, 255));
		canvas.drawText("I am a plane", 350, screenHeight / 100 * 5, paint);
		paint.setTextSize(220);
		canvas.drawText("I'm a train", 50, screenHeight/100*80, paint);

		drawBackground(1);
		// Draw the foreground parallax

		// Unlock and draw the scene
		ourHolder.unlockCanvasAndPost(canvas);
	}
}

We are done!

You can run the game and see the world whizzing by parallax style. Be sure to try different speeds, different and more backgrounds.

Ideally, we should use a viewport solution so that speed and movement happen as a unit of measurement that is independent of the screen resolution. For example, a high-resolution screen will appear to be moving more slowly than a low-resolution screen. I thought I would leave out this issue to focus on the parallax solution. Furthermore, we should really scale the bitmaps relative to the size and resolution of the screen. If for example, you have a more “square” screen than mine your backgrounds might appear a little squashed. When I get round to the simple OpenGL ES series of tutorials we will see how this is solved.

I hope you enjoyed the tutorial. Please let me know either way or if you are stuck.