Building Space Invaders with melonJS and Feature Flags
Growing up as a child of the ’90s has always been a bitter-sweet kind of experience, but it certainly also came with a multitude of benefits. We’ve been exposed to countless priceless moments that have come and passed, moments that stand to make history and which may never be experienced again by newer generations. One such example of a beautiful lived-through historical moment is growing up with the fabled Space Invaders game.
Simple yet memorable, Space Invaders made waves across the world and undoubtedly served as a catalyst for the revival of a previously stale and dying gaming industry that’s now priced at no less than 173.7 billion USD.
What we're going to do
Nostalgia trip aside, the plan here is to rebuild “Space Invaders” in MelonJS while also taking advantage of ConfigCat's feature flag management service to toggle your player's ship from the default one to another, more custom version.
What is MelonJS ?
Well, silly naming scheme aside (which may or may not give you a craving for melons), it’s an:
- actively maintained
- open-source
- JS-powered game engine that’s licensed under MIT
Personally, I’d go for MelonJS 2, as it’s a modern remake of the engine that's perfectly adapted to support ES6 class, inheritance, as well as many other goodies. If you want to learn more about what it can do, check out their docs right here.
What are Feature Flags?
In short, you can visualize a feature flag as a switch that’s used to activate or deactivate certain functionalities that may be present in your application.
Here are some examples of why you may want to use feature flags:
- give early access to new features to only a select few
- targeting specific demographics
- various other testing purposes
- releasing things in a more ordered and stable manner
Why use ConfigCat?
What makes ConfigCat attractive is that they offer a very balanced forever-free plan, which includes a plethora of things, including their entire security stack (while most other competitors would have you pay extra for those). This eliminates any artificial incentive for you to upgrade unless your business organically scales to new requirements.
You could technically create your own in-house feature flag service, but it would make more financial sense to just use an already existent one like ConfigCat’s.
Time to build Space Invaders!
The version of Space Invaders that we’ll be building won’t be anything truly fancy, just your average, stripped-down base game with no extra bells and whistles. We’ll have a set of ships arranged in an 8 by 4 grid rushing toward our ship.
Project structure
The easiest way to start your project is by getting the ES6 boilerplate provided by MelonJS. After that just trim your excess folders and files, and the result should look like this:
src
└── data
| ├── img
└── js
| ├── renderables
| └── stage
├── index.js
├── index.css
├── index.html
├── manifest.js
Here's the repo link of the finished game, in case you want to follow along.
Building the game
To start using MelonJS, we’ll just add the following line to the top of each file where we’ll need to use its functionalities:
import * as me from 'melonjs/dist/melonjs.module.js';
For this project, we’ll add three more files under the js folder:
- constants.js - used to define things like laser’s width and height
- laser.js - used to define the Laser entity
- enemy-manager.js - used to manage the creation and movement of the enemy ships
The entry point for your project is the index.js file where the canvas is prepared and all the prerequisites for the game are preloaded by the onReady()
method:
me.device.onReady(() => {
setTimeout(() => {
if (!me.video.init(
1218, 562,
{parent: 'screen', scale: 'auto', scaleMethod: 'flex-width'})) {
alert('Your browser does not support HTML5 canvas.');
return;
};
me.audio.init('mp3,ogg');
me.loader.crossOrigin = 'anonymous';
me.loader.preload(DataManifest, function() {
me.state.set(me.state.PLAY, new PlayScreen());
me.pool.register('player', PlayerEntity);
me.pool.register('ships', EnemyEntity);
me.pool.register('laser', Laser);
me.state.change(me.state.PLAY);
});
}, 5000);
});
Under the renderables folder we have two files important for the movement and interactions of the ships soon to be battling each other:
- enemy.js - used to define EnemyEntity
- player.js - used to define PlayerEntity
The epic battle will be staged in the stage folder, inside the play.js file where we have the onResetEvent()
, onDestroyEvent()
and checkIfLoss()
methods which will dictate the way our game will work.
All the images we’ll need can be found in the "data/img folder" and we’ll use them in the manifest.js file as such:
const DataManifest = [
{name: 'player', type: 'image', src: 'data/img/player.png'},
{name: 'player2', type: 'image', src: 'data/img/player2.png'},
{name: 'ships', type: 'image', src: 'data/img/ships.png'},
{name: 'bg', type: 'image', src: 'data/img/bg.jpg'}
];
export default DataManifest;
Tips and Tricks
- If you want to add a custom background picture to the game, use the following code to the
OnResetEvent()
method, located in the play.js file:
me.game.world.addChild(new me.ImageLayer(0, 0, {
image: "bg",
repeat: "repeat",
z: 0
}), 0);
- One issue that you may encounter is with the game’s resetting functionality when calling the
checkIfLoss()
function. The bug seems to be caused by thebounds.bottom
argument which may sometimes equal infinity. You can easily go around this bug by just adding the following check at the end of the first if statement in the enemy-manager.js file - at the time of writing, this was at line 40.
if (me.state.current() instanceof PlayScreen) {
me.state.current().checkIfLoss(bounds.bottom);
};
In the end, if all goes well and the Gods of coding are merciful, you should be able to see this:
Using ConfigCat's Feature Flags in Space Invaders
Let's say that I want to change the main ship with a custom version to be displayed to a specific audience. The easiest way to do this without having to change the code and make another deployment of the new version is to implement a feature flag, which can be switched on and off with ease.
I intend to show the custom version of the ship only if the evaluation of the flag is true. And since the application is written in Javascript, I’ll choose ConfigCat's Javascript SDK, for which the process of installing is fairly straightforward and well documented.
Just fire up npm and run npm install configcat-js
, after which just import it in constants.js file via the following line:
import * as configcat from "configcat-js";
The next thing that you need to do is to quickly head over to ConfigCat’s registration page and create a free account for yourself. After which you’re all set to create your first feature flag. I named mine "isMyFirstFeatureEnabled".
I'm now free to go to constants.js and add my SDK key (which you can grab from the ConfigCat Dashboard where you created the flag earlier). Once in the dashboard, you'll see a button in the upper right-hand corner called .
I then create the client like this:
let flag ;
const client = configcat.createClient(sdkKey);
const getFlag = () => flag;
client.getValue("isMyFirstFeatureEnabled", false, value => {
flag=value;
});
Now that the client is in order, we should now hop in the player.js file, import the getFlag()
method from constants.js and use it to load the player with a new ship depending on the flag’s value:
if (getFlag()) {
image = me.loader.getImage("player2");
} else {
image = me.loader.getImage("player");
}
Last but certainly not least, all that’s left to do now is to use the ConfigCat Dashboard, flip the flag to "true" and then reload the game.
BAM! The result should be something like this:
Conclusion
MelonJS is a powerful JS game engine and its extensive documented API serves as a testament to this. It certainly can help you in case you want to have a chance at making the next big game hit. Feature Flags can be outstandingly scalable and useful, and I’m glad that I found ConfigCat to help me out with this.
Here’s the git repo link in case you want to check out this tiny Space Invaders remake and I hope you that you'll get to relive some nice childhood memories playing it.
If you are looking for more articles like this, make sure to check out ConfigCat’s blog posts or you could follow them on your Facebook, Twitter or LinkedIn accounts.