How to Make A Simple HTML5 Game With Enchant.js
This is a post by Tutorial Team member Guts Rodsavas, an iOS development trainer at Software Park Thailand and game developer at Coffee Dog Games. Are you curious about developing cross-platform mobile games that work in a web browser? Well, as you probably know, Apple doesn’t allow Flash to run on iOS devices, and Adobe […] By .
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
How to Make A Simple HTML5 Game With Enchant.js
60 mins
- Introducing enchant.js
- Setting Up the Environment
- Preparing Your Project Structure
- Why Hello There, Ocean!
- Node, Scene and Game: The Basic Concepts
- Object-Oriented Style With enchant.js
- Who Let the Penguin Out!
- A Closer Look at Sprites
- Basic Animation
- Touch Detection
- Ice, Ice Baby
- Collision Detection
- Tally the Score
- A Little Water Music
- Every Penguin Has His Day
- Testing Your Game on Mobile Browsers
- Prepare for iOS Device
- Where To Go From Here?
- Credits
Object-Oriented Style With enchant.js
enchant.js already comes with its own object-oriented framework. Without this, you would have to create a scene and add everything within the game’s onload event. While this is simple, the OOP framework that enchant.js provides makes it easier for you to extend your code, and your code will be cleaner in the long run!
OOP in enchant.js uses the same implementation as Prototype.js, in case you’re familiar with Prototype. So, in order to create a new class, you only need to do the following:
var ClassA = Class.create({
// Constructor
initialize: function(){
},
// Foo method
foo: function(){
}
});
initialize is a constructor function. It will be invoked when you create a new instance of the class.
To add more methods, simply add a comma at the end of the last method before starting the new one.
If you want to create ClassB that is a subclass of ClassA, you would implement ClassB like this:
var ClassB = Class.create( ClassA, {
// Override Foo method
foo: function(){
}
});
Equipped with this knowledge, let’s refactor the previous code using the enchant.js OOP system.
Go to the end of window.onload in main.js (after game.start();) and add these lines:
// SceneGame
var SceneGame = Class.create(Scene, {
// The main gameplay scene.
initialize: function() {
var game, label, bg;
// 1 - Call superclass constructor
Scene.apply(this);
// 2 - Access to the game singleton instance
game = Game.instance;
// 3 - Create child nodes
label = new Label("Hi, Ocean!");
bg = new Sprite(320,440);
bg.image = game.assets['res/BG.png'];
// 4 - Add child nodes
this.addChild(bg);
this.addChild(label);
}
});
The above code creates SceneGame as a subclass of Scene. Let’s go over the code:
- Invoke the constructor of Scene, which is the superclass of your SceneGame, to do any initialization it needs.
- Often you’ll find yourself in need of accessing the game object, especially when you want to access the assets dictionary. Fortunately, the game instance is a singleton, meaning there is only one single instance of Game and it can be accessed from anywhere. This line of code will assign the singleton Game instance to the game variable for later use.
- Create child nodes for the scene, just like before.
- Add the child nodes as before, but this time use this instead of scene because the this variable refers to the current instance of SceneGame. Hence the line is still doing the same thing – that is, adding nodes to your scene node.
With this, you have finally created your first enchant.js class!
It’s time to use SceneGame. Replace the code inside game.onload with the following:
// Once Game finishes loading
console.log("Hi, Ocean!");
var scene = new SceneGame();
game.pushScene(scene);
The game’s onload is now much cleaner. You instantiate a SceneGame object, and add it to the scene stack.
Save your changes and reload the browser. It should be exactly the same as before, except now your code is ready to be extended into a full game!
Who Let the Penguin Out!
It’s time to introduce the ice-water-loving hero of your game – the penguin!
Add res/penguinSheet.png to the preload resource list in window.onload in main.js:
game.preload('res/BG.png',
'res/penguinSheet.png');
Go to the SceneGame constructor and add a new variable named penguin to the first line:
var game, label, bg, penguin;
Then add the following code right after you assign an image to the bg node:
// Penguin
penguin = new Sprite(30,43);
penguin.image = game.assets['res/penguinSheet.png'];
penguin.x = game.width/2 - penguin.width/2;
penguin.y = 280;
The first two lines are similar to what you did with the background. You create a new Sprite node sized 30×43 pixels, and assign the image file to the penguin sprite.
The next two lines set the penguin’s position. Notice how easy it is to access the screen and the penguin’s width. You can access and modify node heights similarly.
Finally, don’t forget to add the penguin to the scene. Otherwise you won’t see it on the screen!
Add the following code right after the line adding the bg node to the scene. Remember that the order in which you add nodes is important!
this.addChild(penguin);
You want the penguin to be on top of the background, but under the label. Therefore, you must add him after the background, but before the label.
Now save your changes and reload the page in your browser to see the current state of your game:
You should now see the penguin on the screen. Your first visual evidence of progress! :]
A Closer Look at Sprites
While the penguin looks like it’s just another Sprite node, it’s slightly different when compared to the background Sprite.
Take a look at how you created the penguin sprite:
penguin = new Sprite(30,43);
Remember what this means? This line created a sprite with a size of 30×43.
However, if you look at the file penguinSheet.png, you’ll see that the image’s size is actually 60×43. Why, that is certainly not 30×43!
So what does this mean? When you instantiate the sprite with a size of 30×43, but assign an image sized 60×43 to it, this is how enchant.js sees the image:
Sprite node in enchant.js treats the image you assign as a sprite sheet. It will use the size you’ve given as its frame size, and assign an index number to each frame. The index will start from 0, counting from left to right and top to bottom.
You can change the animation frame by setting the frame property of a Sprite. This is what you are going to do next!
Basic Animation
Since there are going to be many things going on with your penguin, it’s better to put him into a class of his own. And that’s how your upstart, boulder-challenging penguin prefers it.
Add the code for the Penguin class right below SceneGame in main.js, as follows:
// Penguin
var Penguin = Class.create(Sprite, {
// The player character.
initialize: function() {
// 1 - Call superclass constructor
Sprite.apply(this,[30, 43]);
this.image = Game.instance.assets['res/penguinSheet.png'];
// 2 - Animate
this.animationDuration = 0;
this.addEventListener(Event.ENTER_FRAME, this.updateAnimation);
}
});
Penguin is a subclass of Sprite. As you’ve probably noticed, the line that calls the superclass constructor is a bit different from what you used when you subclassed Scene. This is because a Sprite constructor takes two arguments. To send arguments to your superclass constructor, you pass them as an array in the second argument.
The two lines in section #2 animate your penguin. In the first line, you declare an instance variable, which will be used as a timer for your animation. The second line introduces you to the event system in enchant.js. If you are familiar with ActionScript or Corona development, you’ll find this easy to understand.
Simply put, objects in enchant.js can fire events that other objects might be interested in. If an object is interested in a specific event, you can tell that object to listen for that event and specify functions that should be invoked once that specific event occurs.
Hence, in the above line, you tell the penguin to listen for the ENTER_FRAME event, and call a method named updateAnimation every time this event occurs.
ENTER_FRAME is an event that is fired every frame, similar to the update function in a game loop.
Your Penguin class doesn’t have an updateAnimation method yet. That’s right, you’re going to add one!
Keeping the previous instructions for writing classes in mind, add a comma after the closing curly brace for initialize in the Penguin class, and then add the following code to the Penguin class:
updateAnimation: function (evt) {
this.animationDuration += evt.elapsed * 0.001;
if (this.animationDuration >= 0.25) {
this.frame = (this.frame + 1) % 2;
this.animationDuration -= 0.25;
}
}
Any method that is invoked as part of an event listener can receive one argument, which is the event information. The actual information will differ, depending on the type of event.
For the ENTER_FRAME event, one item of information you can access is the amount of time that has passed since the last frame. This information can be accessed through the elapsed property.
The elapsed property stores time in milliseconds. You can convert it to seconds by multiplying by 0.001. You’ll use the animationDuration variable to keep track of how much time has passed in seconds.
The next line checks if enough time has passed for your penguin to change his animation frame. The if block tells the penguin to flap his wings every 0.25 seconds.
It’s time to use your newly created Penguin class. Go back to where you created the penguin in the SceneGame constructor and replace the code with this:
// Penguin
penguin = new Penguin();
penguin.x = game.width/2 - penguin.width/2;
penguin.y = 280;
this.penguin = penguin;
Since you’ve moved all the sprite-related stuff to the Penguin class, all you need to do is instantiating an instance of the Penguin class and position it.
Save the file and refresh the browser to see what you’ve accomplished.
Your penguin is now moving! Er, at least he’s flapping his flippers. He’s alive – and the water currents are beckoning. Let’s get him on his way.