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.
How the parallax effect 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 to your project. They are shown later in the tutorial.
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.
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.
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.
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 a 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.
- 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.
- In the AndroidManifest.xml file, locate the following line of code, android:name=".ParallaxActivity">
- 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.
- 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.
1 2 |
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 be 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
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(); } } |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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 to 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).
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.
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
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 in 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.
1 2 3 4 |
//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 set up 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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 and 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 around 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.
How do I draw different, random backgrounds?
Not sure exactly what your goal is but you could certainly prepare multiple backgrounds and then randomly choose which ones to use without varying the code much.
I want to call a different background image when the first disappears from the screen to make a scenario that does not repeat itself … if you can explain how I do it and leave the code thank you, I tried in several ways without success.
The classes are designed to use fixed selection of backgrounds so the best solution would be to start again. You could, however load two backgrounds on top of each other and then switch (at a trigger of your choosing) which is drawn last (and therefor visible).
Let me quote : “We will make a reversed copy of the same image and show it to the right of the original(unreversed) image.” Then two images are juxtaposed with a double-sided arrow in between them. And those 2 images are exactly the same not the reverse of one another.
Q1) What is the explanation of putting the same images side by side ?
Quotation again : “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.” Then 2 images follow one after another. Each of those images shows 2 same images ( and not the reversed and non-reversed images) joined together.
Q2) What is the explanation here then ?
Q3) And this commenting system does not let the commenter know via email what is going on i.e. admin approval, replies being added regarding the comments left.
Regards
Yes, you are right they are not reversed in the screen shot. You put them side by side so they can scroll together and when one is completely off-screen, move it so it can be re-used without the player noticing. The code does reverse them, however, with images that look right without being reversed, reversing would be unnecessary but you would then need two source images to start with. Sorry about the comment system.
What’s “gt”? I don’t understad it. “timeThisFrame >= 1″
Many thanks for pointing out these formatting errors. I think they are all fixed now.
Hi, thank you for this tutorial i’m a beginner so.. you know lol, my question is how can i make a bitmap scroll right to left and make it repeat this action?
Hi Phil, this tutorial has a controllable scrolling bitmap in it.
Thanks very much for your tutorial. I would like to ask if I can add a player after finishing this tutorial (the scrolling background). How should I do if I want to add a player in the left-middle area that it can be controlled up/down by touching up/down button? Should I change some code in this tutorial before I add the codes for add a player?
Hi Amelya,
The overall pattern of this program is the same as that of a simple playable program. Take a look at the breakout tutorial and you will notice the same update and draw methods as this tutorial. Just add a class for your new object(s) update it, draw it, add touch handling each frame and you are there.
Thanks for this great tutorial. What I have to change to make it vertically scrollable?
Hi Jaya,
Just move everything around to move vertically. Position the images vertically(different images obviously), move them vertically (probably rename some variables to avoid confusion), remember that zero in the vertical axis is the top of the screen.
Good luck,
John
Can you pls explain, I don’t understand the use case of variables fromRect1,toRect1,fromRect2, and toRect2. and what should be the value for a vertical scroll?
The fromRect… and toRect variables define the section of the bitmap that will be drawn to the screen and the area of the screen it will be drawn to, respectively. Have alook at the diagram at the top of the tutorial that explains that only part of one of the images is required each frame. It is fromRect that controls which part. Hope this helps,
John
Hi John,
Is there anyway I can add/include a Frame Animation, https://www.youtube.com/watch?v=UNrjVaAPrr0&feature=youtu.be or https://www.youtube.com/watch?v=CxXax4GvDrM, to your scrolling background code.
I would just like to add a simple animation to the screen, when the background scene starts.
Kind regards,
Italic
Adding a regular UI element(as in the video) on top of a SurfaceView(as in this tutorial) can be done but slightly awkwardly using a FrameLayout as a base for the SurfaceView. More easy would be to create the sprite sheet animation directly in the same SurfaceView and draw it on top of the background. This following tutorial can be integrated into the parallax background: http://gamecodeschool.com/android/coding-android-sprite-sheet-animations/
Hi John,
Thanks for getting back to me.
I will give it a try and I will let you know how I went.
Also, great job on the tutorials. I know I have learnt alot from them.
Kind regards,
Italic
Hi John,
I was able to split the class up from “Coding Android Sprite Sheet Animations” and place the respective code in the classes from “Coding a Parallax Scrolling Background”, and it works like a charm.
Thanks for all your help.
I am going to try and add sound now as shown in “Programming a Space Invaders Game”.
Thanks again for all your help, it’s appreciated.
Kind regards,
Italic
Good! Thanks for commenting.
Hello, great lesson. I managed to edit it so it scroll vertically from top to bottom.
Now I have question, I have 7 images. And when I use
for(int i=0;i<background.size();i++)
{drawBackground(i)}
it gets really glitchy to draw all of them. Is there any way to speed up code?
You are drawing seven images one frame per update? Should be OK on a modern device but probably very glitchy on emulator.
It’s not even ok on a Xiaomi Redmi Note 7. I guess I need to use less images.
EDIT: Does multithreading helps with this?