Creating a Parallax Scrolling Background in Phaser | Exploring the Art and Design of Game Development

Creating a Parallax Scrolling Background in Phaser

In this tutorial, we'll guide you through the steps of setting up a parallax scrolling background in Phaser. If you have not set up the enviroment, refer to the previous post, part 1. In this new post you will learn to load distinct layers of visual elements such as – clouds, trees, and mountains – and setting different scrolling speeds for each. We'll further refine the visuals by applying tint and alpha effects. Upon completion of this tutorial, you'll have a comprehensive understanding of creating beautiful parallax scrolling backgrounds for your games and interactive projects. Without further ado, let's bring the game to life with an engaging parallax effect!

Setting up the project Structure

To maintain consistent naming throughout our codebase, we'll use an object to represent texture keys, given that vanilla JavaScript does not support enums. This approach prevents naming discrepancies and ensures code clarity.

Please follow these steps:

Create a new folder named consts inside the src folder. Inside the consts folder, create a new file named TexturesKeys.js. By structuring our code this way, we can define and refer to texture keys in a centralized and consistent manner, thereby minimizing the risk of bugs due to misspellings or references to non-existent keys.

Here's what the content of TexturesKeys.js should look like:

export const TexturesKeys = {
  Clouds: "clouds",
  Trees: "trees",
  Mountain1: "mountain1",
  Mountain2: "mountain2",
  Mountain3: "mountain3"
};

Now, to get started with creating the parallax effect, you need the layers for clouds, trees, and mountains. Click on the following link to download them:

Download Layers here These layers represent different depths of the background scene. By moving them at different speeds, we can create the illusion of depth and motion in our game. This download includes all the necessary elements to follow along with this tutorial. Remember to place the downloaded images in the public/assets/ folder.

Preloading assets in Phaser

The next step is to create a new file under src/scenes called Preloader.js Phaser works with a system of "Scenes", which can be thought of as individual states or sections of your game. A common practice is to create a dedicated scene for preloading all assets, which ensures that everything is loaded before the game starts. This is exactly what we are doing with the "Preloader" scene.

Let's break down the code provided:

import Phaser from "phaser";
import TexturesKyes from "../consts/TexturesKeys";

export default class Preloader extends Phaser.Scene {
	constructor() {
		super("preloader");
	}

	preload() {
		this.load.image(TexturesKeys.Clouds, "/assets/clouds.png");
		this.load.image(TexturesKeys.Trees, "/assets/trees.png");
		this.load.image(TexturesKeys.Mountain1, "/assets/mountain1.png");
		this.load.image(TexturesKeys.Mountain2, "/assets/mountain2.png");
		this.load.image(TexturesKeys.Mountain3, "/assets/mountain3.png");
	}
	create() {
        this.scene.start("game")
	}

	update(t, dt) {}
}

Line 1-2: We start by importing Phaser and the TexturesKeys from our previously created constant file.

In line 6, we are creating the Preloader class, which is a subclass of the Scene class in Phaser. We use the super keyword to call the constructor of the Scene class, passing the key "preloader" as an argument. This key is used to identify and manage the preloader scene in Phaser.

Line 8-15: The preload() function is a built-in Phaser method that's invoked when the scene is being initiated. It is commonly used to load game assets. In our case, it's used to load five image assets from the "assets" directory. These images are assigned respective keys ("clouds", "trees", "mountain1", etc.) that will be used to refer to them later in our game.

Line 17: The create() method runs after the preload() function. This is where we can initialize variables. Here we're transferring control to the main scene. Keep in mind that the key must correspond to the one provided in the game scene.

Creating the Parallax Manager

Next, we are going to create a new directory within the src directory, named game. In this newly created directory, we will create a JavaScript file named ParallaxManager.js. After these steps, your directory structure should look like this:


├── src
│   ├── game
│   │   └── ParallaxManager.js

Furthermore, inside the game directory, we are also going to create another new file called Layer.js. This results in the following structure


├── src
│   ├── game
│   │   └── ParallaxManager.js
│   │   └── Layer.js

Next, we open the Layer.js file and add the provided code snippet.

import Phaser from "phaser";

export default class Layer {
	scene;
	layer;
	speedModifier;
	speed;

	constructor(scene, image, speedModifier, speed) {
		this.scene = scene;
		this.layer = image;
		this.speedModifier = speedModifier;
        this.speed = speed
	}

	update(t, dt) {
		this.layer.tilePositionX += this.speedModifier * this.speed * (dt / 1000);
	}
} 

Line 4-7: Here, we declare class variables.

Line 10-12: The constructor for our class. This is a special function that is called when an object is created from a class. This function takes four parameters: scene, image, speedModifier and speed. We use these parameters to initialize our class variables.

Line 16: we define the update function, which is a built-in method in Phaser that is called every frame of the game. This function takes two parameters: t represents the current time since the scene started, and dt represents the time elapsed since the last frame.

Inside the update function, we modify the tilePositionX property of our layer. This property controls the horizontal position of the layer, and by incrementing it, we create the scrolling effect. We increment it by a factor of speedModifier, which determines the speed of the scrolling, multiplied by speed, which represents the overall speed of the layer. Additionally, we divide the time delta dt by 1000 to convert it from milliseconds to seconds, ensuring smooth movement regardless of frame rate.

By adjusting these parameters and updating the tilePositionX property, we achieve the desired parallax effect, where different layers of the background move at different speeds, creating a sense of depth and motion in our game.

Implementing the Parallax Manager Class

We're using the Phaser framework, which provides a built-in game object called TileSprite for this purpose. The TileSprite game object is a type of sprite that has a repeating texture. The texture can be scrolled and scaled and will automatically wrap on the edges, which is perfect for creating an infinite scrolling background, such as a scrolling landscape in a side-scrolling game.

The main advantage of using TileSprite over manually managing and animating several individual sprites for each layer is the performance and the simplicity of implementation. With TileSprite, we only need to load and handle one sprite per layer, which is then repeated as needed by the framework itself.

In the ParallaxManager class, we first create TileSprite objects for each layer of our background, setting each TileSprite's scroll factor to zero. This means that no matter how our camera moves, these TileSprites will stay in place. We then take control of their movement ourselves in the update() method, creating the parallax effect by moving each layer at a different speed.


import Phaser from "phaser";
import TexturesKeys from "../consts/TexturesKeys";
import Layer from "./Layer";

export default class ParallaxManager {
	clouds;
	trees;
	mountain1;
	mountain2;
	mountain3;
	scene;

	constructor(scene) {
		this.scene = scene;
        this.init()
	}

	init() {
		const { width, height } = this.scene.scale;
		const cloud = this.scene.add
			.tileSprite(0, 0, width, height, TexturesKeys.Clouds)
			.setOrigin(0, 0)
			.setScrollFactor(0, 0);

		const mountain3 = this.scene.add
			.tileSprite(0, 0, width, height, TexturesKeys.Mountain3)
			.setOrigin(0, 0)
            .setScrollFactor(0,0);
		const mountain2 = this.scene.add
			.tileSprite(0, 0, width, height, TexturesKeys.Mountain2)
			.setOrigin(0, 0)
			.setScrollFactor(0, 0);

		const mountain1 = this.scene.add
			.tileSprite(0, 0, width, height, TexturesKeys.Mountain1)
			.setOrigin(0, 0)
			.setScrollFactor(0, 0);
		const trees = this.scene.add
			.tileSprite(0, 0, width, height, TexturesKeys.Trees)
			.setOrigin(0, 0)
			.setScrollFactor(0, 0);

		cloud.setTint(0xe0e8e5);
		trees.setTint(0x314448);
		mountain1.setTint(0x536d6c);
		mountain2.setTint(0x7c9a92);
		mountain3.setTint(0xc7d3bf);
		this.scene.cameras.main.setBackgroundColor(0xe0dab8);

		this.clouds = new Layer(this.scene, cloud, 0.03);
		this.mountain1 = new Layer(this.scene, mountain1, 0);
		this.mountain2 = new Layer(this.scene, mountain2, 0.4);
		this.mountain3 = new Layer(this.scene, mountain3, 0);
		this.trees = new Layer(this.scene, trees, 0.35);
	}

	update(t, dt) {
		this.clouds.update(t, dt);
		this.trees.update(t, dt);
		this.mountain2.update(t, dt);
	}
}

Line 2: TexturesKeys is imported.

Line 3: The previously explained Layer class is imported.

Line 7-12: The properties of the parallax manager

Line 14: The constructor of the ParallaxManager class. It takes a scene as a parameter and stores it in the scene property and also calls the init() instance method

Line 19: The init() method. This method sets up the tile sprites for the clouds, trees, and mountains using the tileSprite() method, which creates a sprite that repeats its texture to fill the given width and height. Each sprite is given a tint color with setTint(). The method then creates Layer instances for each of the tile sprites and stores them in the corresponding properties of the ParallaxManager class. Lines 44-47: These lines of code will change the color of the sprites to the specified hexadecimal color value.

Line 58: The update() method. It calls the update() method on each Layer object, passing through the t and dt parameters, which represent the current time and the time difference from the last frame, respectively.

The Grand Finale

Our grand finale! We're back where it all begins - open the Game class.


import Phaser from "phaser";
import TexturesKeys from "../consts/TexturesKeys";
import ParallaxManager from "../game/ParallaxManager";

export default class Game extends Phaser.Scene {
	parallaxMg;
	constructor() {
		super("game");
	}

	preload() {}

	create() {
		this.parallaxMg = new ParallaxManager(this);
	}

	update(t, dt) {
		this.parallaxMg.update(t, dt);
	}
}

Line 4: We import the ParallaxManager class. Line 14: The create() method initializes a new ParallaxManager class, passing the scene (this) as an argument.

Line 19: This is where the magic happens! On every frame, we update the scrolling position of each layer inside the parallax manager class to create the parallax effect. To view the scene in action, navigate to the root directory, where the package.json file is located, and execute the command npm start.

npm run 

Here is the outcome

What's Next

Now that you've mastered the art of creating parallax scrolling backgrounds, why not take it a step further? You could try incorporating these backgrounds into your own game project, or play around with different speeds, layers, and tints to create unique and interesting visual effects. The world of game development is all about creativity and experimentation, so don't be afraid to think outside the box and make your backgrounds as engaging and dynamic as possible!