Phaser Platformer Series: 22 Title and End Screens
posted on 16 August 2021
Now that we have a basic scene setup working, we can start to add some polish to our title and end screens. A nice easy way to add some life to menu screens is particle effects. Phaser has a great particle engine that’s really easy to setup. On top of that we’ll use a custom font from google so it looks less default.
Here is what we’ll be making:
See the Pen
Phaser Platformer Series: 22 Title and End Screens by Digitherium (@digitherium)
on CodePen.
If you are viewing on a mobile, you can open a version of it here without all the codepen chrome taking up screen space so you play it in landscape mode.
In order to load google fonts we need to load google script in the preload function of our titleScreen like this:
titleScreen.preload = function() {
this.load.setBaseURL("assets/");
this.load.image("coin", "coin.jpg");
this.load.image("burst", "burst.png");
this.load.image('hero', 'hero.jpg');
//googles webfont script to load fonts
this.load.script('webfont', 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js');
}
We’re also loading in some graphics assets to use with our particle effects. Let’s take a look at the webfonts first. Before we can write text to screen we need to add some code in our titleScene create function:
WebFont.load({
google: {
families: ['Josefin Sans:700']
},
active: function() {
//our font(s) are loaded!
}
});
This webfont loading script can also be used to load local files (assuming you have the typefaces in the right format). Here were are specifying that we want to use google, and then within that section of the code, we tell it which google font families we want.
We want to load in ‘Josefin San’ at the weight of 700 (that’s bold in this case). We can load multiple fonts in here, by comma separating our strings in quotes. When the font has loaded the active function is called and it’s here we can write text to the screen. Once again, that pesky issue of scope is appearing! We normally write text to the screen using this.add.text, with this referring to our scene. Once inside the webfont loader the scope of this has changed. A simple way around this is to store our scene in a variable before calling the font loader like this:
var scene = this;
Then within the active function of the Webfont loader we can say scene.add.text like this:
scene.add.text(config.width / 2, config.height / 2 + 70, 'SUPER SQUARE BOY!', { fontFamily: 'Josefin Sans', fontSize: 32, color: '#edbc45', align: 'center' }).setShadow(4, 4, "#000000", 2, false, true).setOrigin(0.5);
So altogether it looks like:
//store reference to the scene here because of scope inside the webfont loader
var scene = this;
//Make sure our google font has loaded before we attempt to write text to the screen
WebFont.load({
google: {
families: ['Josefin Sans:700']
},
active: function() {
//eate text using our google font
scene.add.text(config.width / 2, config.height / 2 + 70, 'SUPER SQUARE BOY!', { fontFamily: 'Josefin Sans', fontSize: 32, color: '#edbc45', align: 'center' }).setShadow(4, 4, "#000000", 2, false, true).setOrigin(0.5);
scene.add.text(config.width / 2, config.height / 2 + 120, 'CLICK OR TAP TO PLAY', { fontFamily: 'Josefin Sans', fontSize: 22, color: '#ef5e5e', align: 'center' }).setShadow(4, 4, "#000000", 2, false, true).setOrigin(0.5)
}
});
The key thing here is that we can now have access to the loaded font and can set the fontFamily of the text to be ‘Josefin Sans’. We position the text in the center of the screen using the config with and height and have also offset it on the y axis so it’s a bit lower leaving space for a graphic at the top. We also add a drop shadow and set its origin to be its center.
We preloaded a new graphic called burst. This is a nice radial gradient that we’re going animate spinning round, with our lead character (which is still just a white square!) sat proudly on top:
//add our gradient burst graphic
var burst = this.add.sprite(config.width / 2, config.height / 2 - 40, 'burst');
burst.setScale(0.7);
//make it spin
var burstTween = this.tweens.add({
targets: burst,
angle: 360,
repeat: -1,
ease: 'Linear',
duration: 12000
});
//position our hero sprite in the middle of the burst
this.add.sprite(config.width / 2, config.height / 2 - 40, 'hero');
Pretty standard stuff by now. The sprite is positioned, scaled-down slightly (to 70% of its original size), and then an infinite tween set up so it keeps on rotating. The easing is set to linear so it doesn’t speed up or slow down and is a seamless, endless rotation.
Looking much better already. Next, we’ll add our particle effects. As we want the particle effects in the background, we put this code at the start of our create function:
//create a particle emitter
var particles = this.add.particles('coin'),
//create an area that matches size of game for particles to appear
emitZone = new Phaser.Geom.Rectangle(0, 0, 800, 400),
//create a particle emitter
emitter = particles.createEmitter({
speed: { min: -40, max: 40 },
lifespan: 2000,
//quantity: 10,
scale: { min: 0.1, max: 0.2 },
alpha: { start: 0.6, end: 0 },
blendMode: 'ADD',
emitZone: { source: emitZone }
});
The first thing we specify is what sprite we’ll use for the particles. We’re going to use the coin because we already have it to hand. Next, we create an area where our particles will appear. You can emit particles from one point, for example, the center of the screen but we’re going to use and emitZone for this one, which is an area that we specify. It just makes for a bit more of a chilled-out background effect this way. We specify the emit zone by using Phasers geometry function to create a rectangle the same size as our game. Then, we create our emitter which will spawn and emit particles based on the parameters we give it.
There are loads of things that you can do here to get different types of effects. We’re going for something gentle and abstract, so we want the particles to just bob around then fade away.
We set a lifespan of 2 seconds, so each particle will hang around for that long, and we tell each particle to start at 0.6 opacity and fade to nothing. We also set the particle’s scale to be randomly between 0.1 and 0.2, and give them a little bit of random speed (from -40 to 40) too so they move about. There are some default settings on the emitter, such as frequency which we could play with to decrease the rate of particles. Its default is set to 0, which means it just keeps on creating particles with no time in between each one, adding a higher number such as 100 will add a gap of 100ms between each particle being created, thus slowing it down.
There is also quantity which defaults to 1. If we set this to say 10, we’d have a lot more particles being emitted each time the emitter creates a particle. At the moment it’s just creating one particle at a time, then moving onto the next one in quick succession. If we changed this to 10, it would create 10 at a time, so there would be loads more particles on the screen at any one time, and just a lot more business.
We could write several blog posts digging into particle effects as it’s such a big topic. Feel free to play around with the settings and see what you come up with. I’m happy with these settings as a nice gentle background effect, so moving on.
So we’ve added nice fonts, a spinning gradient graphic, and some interesting particle effects and that’s really lifted it. All that is left to do now, is add the same to the endScreen scene.
Because we’ve already preloaded the assets including the font, we don’t need a preload function. We also don’t need to wait for the webfont to load, so we can add the text to the screen straight away in our create function. It’s just a case of copying over the particle effects and burst sprite and animation and we’re done.
endScreen.create = function() {
var particles = this.add.particles('coin'),
emitZone = new Phaser.Geom.Rectangle(0, 0, 800, 600),
emitter = particles.createEmitter({
speed: { min: -40, max: 40 },
lifespan: 2000,
scale: { min: 0.1, max: 0.2 },
alpha: { start: 0.6, end: 0 },
blendMode: 'ADD',
emitZone: { source: emitZone }
});
var burst = this.add.sprite(config.width / 2, config.height / 2 - 40, 'burst');
burst.setScale(0.7);
var tween = this.tweens.add({
targets: burst,
angle: 360,
repeat: -1,
ease: 'Linear',
duration: 12000
});
//position our hero sprite in the middle of the burst
this.add.sprite(config.width / 2, config.height / 2 - 40, 'hero');
//font has already been loaded, so no need to wait for it
this.add.text(config.width / 2, config.height / 2 + 70, 'GAME OVER!', { fontFamily: 'Josefin Sans', fontSize: 32, align: 'center', color: '#edbc45' }).setShadow(4, 4, "#000000", 2, false, true).setOrigin(0.5);
this.add.text(config.width / 2, config.height / 2 + 120, 'CLICK OR TAP TO PLAY AGAIN', { fontFamily: 'Josefin Sans', fontSize: 22, align: 'center', color: '#ef5e5e' }).setShadow(4, 4, "#000000", 2, false, true).setOrigin(0.5);
this.input.on('pointerdown', function(pointer) {
gameScene.scene.restart();
game.scene.switch('endScreen', 'game');
});
}
Now we have a more complete flow to our game and it’s looking more presentable. It’s time to think about adding some more levels.
Up to this point, we’ve manually placed sprites and scaled platforms as needed. This is a messy way of doing things and will only get us so far. For a platformer, our ideal way of building levels will be using tilemaps. That’s what we’ll take a look at next.
chromeless mobile version
view all the code on codepen
download the source on github.