Photo by Carl Raw on Unsplash

Phaser Game Settings using localStorage

Braelyn Sullivan
6 min readFeb 10, 2020

--

Creating a valuable game experience requires a lot more than a good idea and well-tuned gameplay. Keeping your players engaged might require the opportunity for personalization and tweaks to fit their preferred gaming styles. You may also need to consider some accessibility options like toggles for colorblindness and subtitles for any voiceovers to broaden the audience of your games.

Building off of my previous tutorial, this tutorial will walk you through using the browser’s localStorage to setup basic game settings and user preferences with Phaser 3 and Angular.

Note: I will be breezing through some basic Phaser components to get to the meat of this tutorial — if you encounter something you’re unfamiliar with please check the tutorials here to learn more.

Adding New Features to the Game

Before we can start turning features on and off with game settings, we need to add these features to our game. We’re going to add some music, sound effects and images to kick off our game experience.

First, download these resources or prepare your own image and sound files. There’s a background image (gradient), 2 button images (green_button02, green_button03), 1 .wav file (switch33) and 1 .mp3 (Alexander Ehlers — Twists.mp3). *See end of post for direct links to these resources and attributions

In the game.component.ts file, add this code:

class MainScene extends Phaser.Scene {
...
preload() {
this.load.image('gradient', '../../assets/gradient.png');
this.load.image('button', '../../assets/green_button02.png');
this.load.image('button_pressed',
'../../assets/green_button03.png');
}
create() {
this.add.image(0, 0, 'gradient');
const settingsButton = this.add.image(200, 400,
'button').setInteractive();
const settingsButtonText = this.add.text(0, 0, 'Settings', { color:
'#000', fontSize: '28px' });
Phaser.Display.Align.In.Center(settingsButtonText,
settingsButton);
settingsButton.on('pointerdown', () => {
settingsButton.setTexture('button_pressed');
}).on('pointerup', () => {
settingsButton.setTexture('button');
});
}
}

This code creates a clickable button on the main scene. When you click the button, the texture of the button image swaps to the pressed version. This creates visual feedback to the player that the button has been clicked.

Next, I want to add a sound effect to play when the player clicks a button, giving them aural feedback as well. In game.component.ts :

preload() {
...
this.load.audio('buttonSound', '../../assets/switch33.wav');
}
create() {
...
settingsButton.on('pointerdown', () => {
...
this.sound.play('buttonSound');
})...
}

Now, when a player clicks the button they will see the button pushed in and will hear the sound we’ve tied to the click.

Finally, let’s add some background music to complete the sensory experience. In game.component.ts :

preload() {
...
this.load.audio('backgroundMusic', '../../assets/Alexander Ehlers
- Twists.mp3');
}
create() {
...
const music = this.sound.add('backgroundMusic', {
mute: false,
volume: 1,
rate: 1,
loop: true,
delay: 200
});
music.play();
...
}

Adding Settings Toggles

Music and sound effects are essential pieces to any game — but not everyone enjoys them all the time. When adding music or sound effects, you should also provide a way for the player to turn the sound off.

First, we need to create a new scene to direct the player to when they want to make changes to their settings. At the end of game.component.ts add this code:

class SettingsMenu extends Phaser.Scene {
constructor() {
super({ key: 'settings' });
}
create() {
this.add.text(250, 40, 'Settings', {
fontSize: '56px', color: '#ffffff'
});
this.add.text(200, 220, 'Sound Effects',
{ fontSize: '28px', color: '#ffffff' });
const soundFxButton = this.add.image(550, 235,
'button').setInteractive();
const soundFxText = this.add.text(0, 0, 'On', { fontSize:
'28px', color: '#000000' });
Phaser.Display.Align.In.Center(soundFxText, soundFxButton);
this.add.text(200, 350, 'Music',
{ fontSize: '28px', color: '#ffffff'});
const musicButton = this.add.image(550, 365, 'button')
.setInteractive();
const musicText = this.add.text(0, 0, 'On', { fontSize:
'28px', color: '#000000' });
Phaser.Display.Align.In.Center(musicText, musicButton);
}
}

And up at the top, update your game config to include the new scene you created:

this.config = {
type: Phaser.AUTO,
height: 600,
width: 800,
scene: [MainScene, SettingsMenu],
parent: 'gameContainer',
physics: {
default: 'arcade',
arcade: {
gravity: { y: 100 }
}
}
};

Now, wire up the settings button in MainScene to direct the user to SettingsMenu :

settingsButton.on('pointerdown', () => { ... })
.on('pointerup', () => {
this.scene.launch('settings');
this.scene.stop();
});

We’ve got the setup — now it’s time to put those toggles to use. We will setup our localStorage interfaces and use it to hold our user’s preferences. Click here for a basic explanation of localStorage usage.

In MainScene we’re going to create a variable to hold the game settings, query the localStorage for any items matching our game’s name `myGameSettings` and creating a default if no items are found:

class MainScene extends Phaser.Scene {
gameSettings: any;
defaultSettings: any = [
{ setting: 'music', value: true },
{ setting: 'sfx', value: true }
];
create() {
this.gameSettings =
JSON.parse(localStorage.getItem('myGameSettings'));
if (this.gameSettings === null || this.gameSettings.length <= 0)
{
localStorage.setItem('myGameSettings',
JSON.stringify(this.defaultSettings));
this.gameSettings = this.defaultSettings;
}
...
}

Then, we’ll modify SettingsMenu to get and update the localStorage items:

class SettingsMenu extends Phaser.Scene {
gameSettings: any;
create() {
this.gameSettings =
JSON.parse(localStorage.getItem('myGameSettings'));
... const soundFxText = this.add.text(0, 0, this.gameSettings[1]
.value === true ? 'On' : 'Off', { fontSize:'28px', color:
'#000000' });
soundFxButton.on('pointerdown', () => {
soundFxButton.setTexture('button_pressed');
}).on('pointerup', () => {
soundFxButton.setTexture('button');
if (this.gameSettings[1].value) {
this.gameSettings[1].value = false;
soundFxText.text = 'Off';
} else {
this.gameSettings[1].value = true;
soundFxText.text = 'On';
}
localStorage.setItem('myGameSettings',
JSON.stringify(this.gameSettings));
});
... const musicText = this.add.text(0, 0, this.gameSettings[0]
.value === true ? 'On' : 'Off', { fontSize:'28px', color:
'#000000' });
musicButton.on('pointerdown', () => {
musicButton.setTexture('button_pressed');
}).on('pointerup', () => {
musicButton.setTexture('button');
if (this.gameSettings[0].value) {
this.gameSettings[0].value = false;
musicText.text = 'Off';
} else {
this.gameSettings[0].value = true;
musicText.text = 'On';
}
localStorage.setItem('myGameSettings',
JSON.stringify(this.gameSettings));
});
}

You should now be able to toggle the sound effects and music by clicking the buttons. When you refresh your game, the previously set values will be returned from localStorage allowing you to maintain these values even after the player has left your site.

The last thing we need to do is make our game reflect the user’s preferences. In MainScene we need to wrap our background music with a conditional tied to the gameSettings object:

const music = this.sound.add(...);
if (this.gameSettings[0].value) {
music.play();
}

Then, we need to update our button sound effect calls with a conditional tied to the gameSettings object:

settingsButton.on('pointerdown', () => {
...
if (this.gameSettings[1].value) {
this.sound.play('buttonSound');
}
})

Now, you should be able to toggle the settings at will and the reloaded main scene will reflect the settings you have chosen.

Additional Considerations

Please keep in mind that localStorage items are not protected. A tech-savvy user will be able to open up their developer tools and make modifications to their localStorage items. To add an additional layer of security to your game settings, consider adding an encrypt/decrypt process to your setting and retrieving of localStorage items.

If you’re planning to do a gradual roll-out of features where the items in your localStorage settings may change, it could also be useful to add a date-timestamp to your settings object to check for frequent updates.

You can download the completed tutorial here: https://github.com/brsullivan/phaser-angular-app-step2

Game Resources used in this tutorial with many thanks:
Sound effects from https://opengameart.org/content/51-ui-sound-effects-buttons-switches-and-clicks (www.kenney.nl)
Music from https://opengameart.org/content/free-music-pack
UI Images from https://opengameart.org/content/ui-pack (www.kenney.nl)

Thanks for reading this tutorial! Please feel free to leave me any feedback or questions in the comments.

--

--

Braelyn Sullivan
Braelyn Sullivan

Written by Braelyn Sullivan

Front End Solutions Consultant & Full-Stack developer. Avid crafter & cat lover. Charlotte, NC

No responses yet