Phaser 3 HTML5 Template

When you're developing Phaser 3 HTML5 games, it's good to have a template that you can use to start off with. The template will allow you to create all the basics of a game that you need, so you can then focus on spending your time developing the actual game. We've done a series of tutorials explaining the various parts that make up a game, and so this Template puts those all together so that you now have a skeleton for each of your games.

Phaser 3 Template

We've previous looked at:

Now we are going to put all of these together to build our Template that we'll be using for all our games. We're going to introduce three new scenes into our game:

  • BootScene
  • InstructionScene
  • EndScene

The BootScene is used at the very beginning before the Preloader is called. We may want to load some small assets into the preloader, such as logo or make a communication to the server or something like that.

The InstructionScene is where we place information about how to play the game. We'll add two buttons to the TitleScreen - one for starting the game and one for viewing the game instructions.

The EndScene is called when we have game over. We may use this scene to send a score to the server or display the highscore chart.

You can find the full template code at the bottom of this tutorial.

Game Structure

We'll load our Phaser game using a simple index.html file. Here we load the Phaser JS library and our main game file main.js:

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Template Phaser Game</title>
    <script src="http://nh.patchesoft.com/scripts/phaser/phaser.min.js"></script>
</head>
<body>
<script type="module" src="http://nh.patchesoft.com/scripts/phaser/games/template/main.js"></script>
</body>
</html>

Main.js

import BootScene from './BootScene.js';
import PreloadScene from './PreloadScene.js';
import TitleScene from './TitleScene.js';
import InstructionScene from './InstructionScene.js';
import GameScene from './GameScene.js';
import EndScene from './EndScene.js';

// Load our scenes
var bootScene = new BootScene();
var preloadScene = new PreloadScene();
var titleScene = new TitleScene();
var instructionScene = new InstructionScene();
var gameScene = new GameScene();
var endScene = new EndScene();




//* Game scene */
var config = {
  type: Phaser.AUTO,
  width: 800,
  height: 600,
};
var game = new Phaser.Game(config);

// load scenes
game.scene.add('BootScene', bootScene);
game.scene.add('PreloadScene', preloadScene);
game.scene.add('TitleScene', titleScene);
game.scene.add('InstructionScene', instructionScene);
game.scene.add("GameScene", gameScene);
game.scene.add("EndScene", endScene);


// start title
game.scene.start('BootScene');

In main.js, you can see we import all our scenes that we need and then add them to the main game for use. We start the game using the BootScene.

BootScene

export default class BootScene extends Phaser.Scene {

	constructor() {
		super('BootScene');
	}

	preload() {
		this.load.image('logo', 'images/tut/icon.png');
	}

	create() {
		this.scene.start("PreloadScene");
	}

}

PreloaderScene

export default class PreloadScene extends Phaser.Scene {

	constructor() {
		super('PreloadScene');
	}

	preload() {

		// Add loading screen bars
		this.graphics = this.add.graphics();
		this.newGraphics = this.add.graphics();
		var progressBar = new Phaser.Geom.Rectangle(200, 200, 400, 50);
		var progressBarFill = new Phaser.Geom.Rectangle(205, 205, 290, 40);

		this.graphics.fillStyle(0xffffff, 1);
		this.graphics.fillRectShape(progressBar);

		this.newGraphics.fillStyle(0x3587e2, 1);
		this.newGraphics.fillRectShape(progressBarFill);

		var loadingText = this.add.text(250,260,"Loading: ", { fontSize: '32px', fill: '#FFF' });


		this.load.on('progress', this.updateBar, {newGraphics:this.newGraphics,loadingText:loadingText});
		this.load.on('complete', this.complete, {scene:this.scene});

		// Any Assets you want to load in
		this.load.image('background', 'images/tut/background.png');
		for(var i =0;i<30;i++) {
			this.load.image('background_'+i, 'images/tut/background.png');
		}
	}

	updateBar(percentage) {
		if(this.newGraphics) {
			this.newGraphics.clear();
			this.newGraphics.fillStyle(0x3587e2, 1);
			this.newGraphics.fillRectShape(new Phaser.Geom.Rectangle(205, 205, percentage*390, 40));
		}
		percentage = percentage * 100;
		this.loadingText.setText("Loading: " + percentage.toFixed(2) + "%");
		console.log("P:" + percentage);
	}

	complete() {
		console.log("COMPLETE!");
		this.scene.start("TitleScene");
	}

	create() {
		
	}

}

TitleScene

export default class TitleScene extends Phaser.Scene {

	constructor() {
		super("TitleScene");
	}

	preload() {

	}

	create() {
		 var bg = this.add.sprite(0,0,'background_1');
		 bg.setOrigin(0,0);

		var startText = this.add.text(100,100, 'Start Game');
		startText.setInteractive({ useHandCursor: true });
		startText.on('pointerdown', () => this.startButton());

		var optionText = this.add.text(100,200, 'Instructions');
		optionText.setInteractive({ useHandCursor: true });
		optionText.on('pointerdown', () => this.instructionButton());
	}

	startButton() {
		console.log("starting ...");
		this.scene.start('GameScene');
	}

	instructionButton() {
		console.log("instructions ...");
		this.scene.start('InstructionScene');
	}

}

InstructionScene

export default class InstructionScene extends Phaser.Scene {

	constructor() {
		super("InstructionScene");
	}

	preload() {

	}

	create() {
		 var bg = this.add.sprite(0,0,'background_1');
		 bg.setOrigin(0,0);

		 var text = 'Welcome to the game. Here are the instructions on how to'+
		 'play the game. Here you can explain various points of the game, display'+
		 'images etc.'

		 var startText = this.add.text(100,100, text);

		 // Add go back button to title screen
		var backText = this.add.text(100,500, 'Go Back');
		backText.setInteractive({ useHandCursor: true });
		backText.on('pointerdown', () => this.backButton());
		
	}

	backButton() {
		this.scene.start('TitleScene');
	}

}

 

These four scenes shouldn't really be anything new. We have our bootscene to load the game logo (which we can display in the preloader if we want-it's just an example). We add two buttons to our TitleScene, one which loads InstructionScene and the other which loads of GameScene.

GameScene.js:

export default class GameScene extends Phaser.Scene {

	constructor() {
		super("GameScene");
	}

	init() {
		// game variables
		this.score = 0;
		this.lives = 3;
		this.speed= 1.5;
		this.dragon_move = 1;
		this.score_text;
		this.lives_text;
	};

	preload() {
		// lets preload some images that we can use in our game (add these to the preloader)
		this.load.image('background', 'images/tut/background.png');
		this.load.image('player', 'images/tut/warrior.png');
		this.load.image('dragon', 'images/tut/pet_dragon_new.png');
		this.load.image('gold', 'images/tut/icon.png');
	}

	create() {
	   // add the background
	   var bg = this.add.sprite(0, 0, 'background');
	   bg.setOrigin(0,0);

	   // add score text & game text to screen
	   this.scoreText = this.add.text(100, 16, 'score: ' + this.score, { fontSize: '32px', fill: '#000' });
	   this.liveText = this.add.text(16, this.sys.game.config.height-50, 'Lives: ' + this.lives, {fontSize: '32px', fill: '#000'});

	   // add player
	   this.player = this.add.sprite(100, 150, 'player');
	   this.player.setScale(0.3);

	   // add monster
	   this.dragon = this.add.sprite(350, 150, 'dragon');
	   this.dragon.setScale(0.1);

	   // add gold
	   this.gold = this.add.sprite(650, 150, 'gold');
	   this.gold.setScale(0.5);

	}

	update() {

	  // Is mouse click down?
	  if (this.input.activePointer.isDown) {
	  	// move player along the x-axis at a rate this.speed pixels
	    this.player.x += this.speed;
	  }


	  if(this.dragon.y >= 500) {
	  	// Enemy movement
	  	this.dragon_move = -1;
	  } else if(this.dragon.y <= 100) {
	  	// Enemy movement
	 	 this.dragon_move = 1;
	  }

	  this.dragon.y += this.dragon_move;

	  if (Phaser.Geom.Intersects.RectangleToRectangle(this.player.getBounds(), this.dragon.getBounds())) {
	    this.lives--;
	  	this.liveText.setText("Lives: " + this.lives);
	  	this.end();
	  }

	  if (Phaser.Geom.Intersects.RectangleToRectangle(this.player.getBounds(), this.gold.getBounds())) {
	    this.score +=50;
	  	this.scoreText.setText("Score: " + this.score);
	  	this.end();
	  }

	}


	end() {
		if(this.lives <= 0) {
			this.scene.start("EndScene");
		} else {
			this.create();
		}
	}

}

This is the game logic we built in the first tutorial. It's wrapped in it's own scene now so it allows us to switch it in and out on a button click. When the player runs out of lives, we now send them to the EndScene. We can move the preload content to our preloader too.

EndScene.js

export default class EndScene extends Phaser.Scene {

	constructor() {
		super("EndScene");
	}

	create() {
		 var bg = this.add.sprite(0,0,'background_1');
		 bg.setOrigin(0,0);

		 var text = 'Game Over'

		 var startText = this.add.text(100,100, text);

		 // Add go back button to title screen
		var backText = this.add.text(100,500, 'Go Back');
		backText.setInteractive({ useHandCursor: true });
		backText.on('pointerdown', () => this.backButton());
		
	}

	backButton() {
		this.scene.start('TitleScene');
	}

}

Which basically just gives us an option to go back to the TitleScene.

That is our template. We've got all the basics we need for game development, we now just really need to focus on User Interface and making all these scenes perfect. We can also just focus on the game logic in GameScene.js. We'll be using this template structure for our upcoming game tutorials.

Full Phaser 3 Template Code: https://www.patchesoft.com/uploads/GameTemplatePhaser.zip




Enjoyed that? Check These Posts Out

Fullcalendar with PHP and CodeIgniter - Adding Events - Part 3

Datatables with CodeIgniter – Server Side Sorting – Part 3

2019 Acer Predator Helios 300 Gaming Laptop Review (PH315-52-78VL) - A great gaming machine

HTML For Beginners Part 3

Article Comments

Let us know your thoughts below by adding a quick comment!

Leave A Comment