How To Make a Cross-Platform Game with Cocos2D Javascript Tutorial: Getting Started
In this tutorial, you will port the raywenderlich.com classic Ninjas Going Pew-Pew game to Cocos2D-Javascript. I like implementing this game when learning new frameworks because it’s simple, but covers the most important aspects of making a game. By Ray Wenderlich.
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 Cross-Platform Game with Cocos2D Javascript Tutorial: Getting Started
35 mins
This is not a picture – it’s a game! Click to play!
Did you know you can make a Cocos2D game that runs on the iPhone, Mac, Android, and web all sharing the same exact code?
Don’t believe me? Try clicking the screenshot over on the right – it’s actually a Cocos2D game!
You can do this with an amazing new Cocos2D technology called Cocos2D Javascript. It allows you to write your gameplay code once, and run it anywhere – with full native speed.
The only problem is this new techology is a bit under-documented at the moment. But never fear – we’ve got you covered! :]
In this tutorial, you will port the raywenderlich.com classic Ninjas Going Pew-Pew game to Cocos2D-Javascript. I like implementing this game when learning new frameworks because it’s simple, but covers the most important aspects of making a game.
This tutorial is for both people completely new to Cocos2D as well as those who are already familiar with Cocos2D-iOS and want to learn Cocos2D Javascript.
However, this tutorial assumes you have some basic familiarity with Javascript. If you are new to Javascript, I recommend the book Javascript: The Definitive Guide – this is what I used to get familiar with the language.
Keep reading to become a Cocos2D-Javascript ninja!
About Cocos2D Javascript
Before you start coding, it’s important to understand what Cocos2D Javascript is, and how it works.
The developers of three variants of Cocos2D (cocos2d-iphone, cocos2d-x, and cocos2d-html5) that have teamed up to have a coordinated release that all share the same Javascript API.
The basic idea is you write your core gameplay code in Javascript. Each variant of Cocos2D can then run this Javascript code:
- cocos2d-iphone and cocos2d-x use a library called SpiderMonkey to run the Javascript code you write. But under the hood, all of the core Cocos2D framework code itself is still written in OpenGL/Objective-C/C++, so it still runs very fast.
- cocos2d-html5 runs the Javascript natively, as you might expect.
In addition, the CocosBuilder scene designer is fully compatible with the Javascript API.
To see an example of a full game, check out my January One Game A Month entry: Confinement. This game is made with the Javascript bindings so runs on the web, iOS, Mac, and more.
Cocos2D Javascript Bindings is a brand new technology, and so still has a bit of wrinkles. But it looks to be the future of the framework, so it’s definitely something worth learning and paying attention to!
Which Comes First: The Chicken or the Framework?
So in summary, you write your Javascript code once and can run it using any of the above game frameworks.
But you’ve got to start with one framework, and I’ve found the easiest to use while you’re in the initial development stage is cocos2d-htlm5. This is because the framework itself is also written in Javascript, so when you are debugging you can step into the framework code when necessary and get better error messages.
So that’s what you’ll do in this tutorial – you’ll make the game initially with cocos2d-html5 (for the web) and then later on you’ll use the same code in the other frameworks.
Getting Started
First, download the starter project for this tutorial. Unzip the file and you should see a directory structure like the following:
The starter project contains the following folders:
- Art: The images for the simple game you’ll be making – a monster, a ninja, and his ninja star.
- Platform: Four empty directories for each platform. You’ll be filling those in later in the tutorial – I included the empty directories to give you good structure.
- Sounds: The background music and the “pew-pew” sound effect, made by yours truly.
Note the starter project does not actually contain any code. That’s your job! :]
Hello, Cocos2D-Javascript!
Are you ready to finally see what this magical cross platform Javascript code looks like? Let’s try it out, and create a simple Cocos2D scene that displays hero sprite.
When you are referencing art, images, and other assets in Cocos2D-Javascript, you need to include them in a special array called g_ressources (yes, the typo is on purpose!) so the framework can load them. So the first step is to add the hero sprite into this special array.
So create a new file named Cocos2DSimpleGame\Src\resource.js with your favorite text editor (lately I’m liking Sublime Text 2), and replace the contents with the following:
var dirArt = "Art/";
var s_player = dirArt + "player.png";
var g_ressources = [
{type:"image", src:s_player}
];
This just adds a single image to your list of resources – the player image. Later on you’ll add the rest of the Art and Sounds to this file, but this is all you need for now.
Next, you’ll create a simple Cocos2D layer to display this image. Create a new file named Cocos2DSimpleGame\Src\MainLayer.js and replace the contents with the following:
// 1
var MainLayer = cc.LayerColor.extend({
// 2
ctor:function() {
this._super();
// 3
cc.associateWithNative( this, cc.LayerColor );
},
// 4
onEnter:function () {
this._super();
// 5
var player = cc.Sprite.create(s_player);
// 6
player.setPosition(player.getContentSize().width / 2, winSize.height / 2);
// 7
this.addChild(player);
}
});
Let’s go over this line by line:
- This creates a new class called MainLayer that extends from Cocos2D’s LayerColor class. Note that in Cocos2D Javascript bindings, all Cocos2D classes have the cc prefix.
- Creates a constructor for the class, that calls the superclass’s constructor.
- In Cocos2D Javascript bindings, whenever you derive from a Cocos2D class you have to call this method to associate it with the appropriate native class.
- When a node is added for the first time to a scene, Cocos2D calls onEnter on it. So this is a good place to put initialization code for a layer.
- This line creates a sprite and puts it in a variable named player. Note for the name of the sprite you pass in the constant s_player that you created earlier.
- Sets the position of the sprite to be the middle-left of the screen. winSize is a handy constant you will define later.
- Finally, adds the player sprite to the layer.
Then, add the following methods to the bottom of the file:
// 1
MainLayer.create = function () {
var sg = new MainLayer();
if (sg && sg.init(cc.c4b(255, 255, 255, 255))) {
return sg;
}
return null;
};
// 2
MainLayer.scene = function () {
var scene = cc.Scene.create();
var layer = MainLayer.create();
scene.addChild(layer);
return scene;
};
These are just two helper methods I like to create.
- The first is a helper method to create a new instance of the MainLayer.
- The second is a helper method to create a new scene and add the MainLayer as a child.
And that’s it for MainLayer.js for now. The best part about it is the code you just wrote is cross-platform and will work as-is on iOS, Android, and more!
Hello, Cocos2D-HTML5!
As I mentioned earlier, you will first get the HTML5 version of this game working first, then you’ll switch to the other platforms later in this series.
So download the latest version of Coos2D-HTML5, which is v2.1.1 at the time of writing this tutorial. Unzip the directory and save it somewhere safe on your hard drive.
Then, inside the Cocos2D-HTML5 directory, copy the cocos2d, CocosDenshion, and extensions directory into the Cocos2DSimpleGame\Platform\HTML5 directory from your starter kit:
This copies all of the Cocos2D-HTML5 framework code into a subdirectory of your project so you can reference it easily. Note that you won’t actually ship your game like this – there’s a better way you’ll learn more about in part 2 of this series – but this is great for debugging and development.
Next, create a new file named Cocos2DSimpleGame\index.html and replace the contents with the following:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Cocos2D-JS Simple Game Demo | raywenderlich.com</title>
</head>
<body style="text-align: center;background: #f2f6f8;">
<img style="clear:both;margin-bottom: 20px" src="logo.png"/>
<div></div>
<div style="display:inline-block;width:auto; margin: 0 auto; background: black; position:relative; border:5px solid black; border-radius: 10px; box-shadow: 0 5px 50px #333">
<canvas id="gameCanvas" width="800" height="450"></canvas>
</div>
<script src="cocos2d.js"></script>
</body>
</html>
This is some simple HTML to present a Cocos2D view in the middle of the page. Don’t worry if you’re rusty on HTML – you can use this as a template and tweak it for your needs.
There are two important tags to point out:
<canvas id="gameCanvas" width="800" height="450"></canvas>
This sets up the HTML5 canvas where the Cocos2D drawing occurs and gives it the “gameCanvas” id that the framework will look for. If you want it to be a different size (like in the header of this tutorial), you can just change the numbers here.
<script src="cocos2d.js"></script>
This tells the browser to look for (and run) a Javascript file called cocos2d.js, which you haven’t written yet.
So let’s add that next! Create a new file a new file named Cocos2DSimpleGame\cocos2d.js and replace the contents with the following:
(function () {
var d = document;
var c = {
// 1
menuType:'canvas',
COCOS2D_DEBUG:2,
box2d:false,
chipmunk:false,
showFPS:true,
frameRate:60,
loadExtension:true,
tag:'gameCanvas',
// 2
engineDir:'./Platform/HTML5/cocos2d/',
appFiles:[
'./Src/resource.js',
'./Src/MainLayer.js',
'./Src/main.js'
]
};
// 3
window.addEventListener('DOMContentLoaded', function () {
var s = d.createElement('script');
if (c.SingleEngineFile && !c.engineDir) {
s.src = c.SingleEngineFile;
}
else if (c.engineDir && !c.SingleEngineFile) {
s.src = c.engineDir + 'platform/jsloader.js';
}
else {
alert('You must specify either the single engine file OR the engine directory in "cocos2d.js"');
}
document.ccConfig = c;
s.id = 'cocos2d-html5';
d.body.appendChild(s);
});
})();
This file is mostly boilerplate, however there are a few sections you might want to tweak so let’s go over it.
- These are various Cocos2D settings, such as the debug level for the framework and which libraries to enable (Box2D, etc).
- Here you specify where the Cocos2D framework code resides – remember how you copied it into the Platform/HTML5/cocos2d directory? You also specify all the Javascript files in your game.
- This is just some boilerplate that starts the Cocos2D framework running.
You may have spotted that the appFiles in section 2 listed a file named main.js, but you haven’t written that yet. That is the last file you have to write to get this all working.
So create a new file named Cocos2DSimpleGame\Src\main.js and replace the contents with the following:
var cocos2dApp = cc.Application.extend({
config:document['ccConfig'],
ctor:function (scene) {
this._super();
this.startScene = scene;
cc.COCOS2D_DEBUG = this.config['COCOS2D_DEBUG'];
cc.initDebugSetting();
cc.setup(this.config['tag']);
cc.Loader.getInstance().onloading = function () {
cc.LoaderScene.getInstance().draw();
};
cc.Loader.getInstance().onload = function () {
cc.AppController.shareAppController().didFinishLaunchingWithOptions();
};
cc.Loader.getInstance().preload(g_ressources);
},
applicationDidFinishLaunching:function () {
var director = cc.Director.getInstance();
director.setDisplayStats(this.config['showFPS']);
director.setAnimationInterval(1.0 / this.config['frameRate']);
// 1
director = cc.Director.getInstance();
winSize = director.getWinSize();
centerPos = cc.p( winSize.width/2, winSize.height/2 );
director.runWithScene(new this.startScene());
return true;
}
});
// 2
var director;
var winSize;
var centerPos;
var myApp = new cocos2dApp(MainLayer.scene);
To run your game, you need to create a class that derives from cc.Application – and that is exactly what this does here. It has an applicationDidFinishLaunching method, just like in iOS.
Most of this is boilerplate, except for the two sectoins I noted:
- Initializes those global helper variables I mentioned earlier.
- Declares the global variables, and specifies the scene to run (MainLayer.scene – that helper method you wrote earlier to create a scene with the MainLayer in it).
And you’re finally done! To test this out, open index.html in the web browser of your choice. Note that I have had best luck with Firefox, as Safari doesn’t always work with local debugging.
If all goes well, you should see your ninja appear on the screen!
Moving Monsters
Next you want to add some monsters into your scene for your ninja to combat. To make things more interesting, you want the monsters to be moving – otherwise there wouldn’t be much of a challenge! So let’s create the monsters slightly off screen to the right, and set up an action for them telling them to move to the left.
First, open Cocos2DSimpleGame\Src\resource.js and modify the list of resources to include the other two images:
var dirArt = "Art/";
var s_player = dirArt + "player.png";
var s_monster = dirArt + "monster.png";
var s_projectile = dirArt + "projectile.png";
var g_ressources = [
{type:"image", src:s_player},
{type:"image", src:s_monster},
{type:"image", src:s_projectile}
];
Then open Cocos2DSimpleGame\Src\MainLayer.js and replace the start of the file with the following:
var MainLayer = cc.LayerColor.extend({
_monsters:[],
ctor:function() {
// Rest of file...
This creates an instance variable for the list of monsters in the scene, and initializes the list to an empty array.
Next add a comma after the onEnter method, and add this new method:
addMonster:function() {
var monster = cc.Sprite.create(s_monster);
// Determine where to spawn the monster along the Y axis
var minY = monster.getContentSize().height / 2;
var maxY = winSize.height - monster.getContentSize().height / 2;
var rangeY = maxY - minY;
var actualY = (Math.random() * rangeY) + minY; // 1
// Create the monster slightly off-screen along the right edge,
// and along a random position along the Y axis as calculated above
monster.setPosition(winSize.width + monster.getContentSize().width/2, actualY);
this.addChild(monster); // 2
// Determine speed of the monster
var minDuration = 2.0;
var maxDuration = 4.0;
var rangeDuration = maxDuration - minDuration;
var actualDuration = (Math.random() % rangeDuration) + minDuration;
// Create the actions
var actionMove = cc.MoveTo.create(actualDuration, cc.p(-monster.getContentSize().width/2, actualY)); // 3
var actionMoveDone = cc.CallFunc.create(function(node) { // 4
cc.ArrayRemoveObject(this._monsters, node); // 5
node.removeFromParent();
}, this);
monster.runAction(cc.Sequence.create(actionMove, actionMoveDone));
// Add to array
monster.setTag(1);
this._monsters.push(monster); // 6
}
I’ve spelled out things in a verbose manner here to make things as easy to understand as possible. The first part should make sense based on what we’ve discussed so far: you do some simple calculations to determine where you want to create the object, set the position of the object, and add it to the scene the same way you did for the player sprite.
I’ll explain the rest of the code in two different ways, based on whether you’re already familiar with the Cocos2D iOS API or not.
[spoiler title=”I’m Familiar with Cocos2D-iOS”]
Here are some things to point out for those transitioning to Cocos2D-Javascript from Cocos2D-iOS:
- Javascript has various handy built-in libraries/functions, like Math.random(). You can find a good reference in the Javascript book I recommended.
- Instead of using dot syntax like monster.position in Objective-C, you always have to call setters like setPosition() with the Javascript bindings.
- cc.p is the equivalent of ccp.
- You can either pass in the name of a method (like this.monsterMoveDone) to cc.CallFunc.create, or you can pass in an anonymous function like you see here (which is similar to using CCCallBlock in Objective-C).
- Cocos2D has a helper function to remove an element from a Javascript array: cc.ArrayRemoveObject.
- In Javascript you use this, not self. I can’t tell you how many times I forget this and use self out of habit, causing everything to fail miserably, gah!
[/spoiler]
[spoiler title=”I’m Completely New to Cocos2D”]
The new element here is adding actions. Cocos2D provides a lot of extremely handy built-in actions you can use to animate your sprites, such as move actions, jump actions, fade actions, animation actions, and more. Here you use three actions on the monster:
- cc.MoveTo: You use the cc.MoveTo action to direct the object to move off-screen to the left. Note that you can specify the duration for how long the movement should take, and here you vary the speed randomly from 2-4 seconds.
- cc.CallFunc: The cc.CallFunc action allows you to specify a callback function to run when the action is performed. You can either pass in the name of a function (like this.monsterMoveDone) or you can use an anonymous function like shown here. In this game, you add some code to remove the moster from the game (and the monsters array) after it moves offscreen to the left. This is important so that you don’t leak memory over time by having tons of unused sprites sitting off-screen. Note that there are other (and better) ways to address this problem such as having reusable arrays of sprites, but for this beginner tutorial you are taking the simple path.
- cc.Sequence: The cc.Sequence action allows you to chain together a sequence of actions that are performed in order, one at a time. This way, you can have the cc.MoveTo action perform first, and once it is complete perform the cc.CallFunc action.
[/spoiler]
Back to Business
That’s it for explanations – now let’s make sure your addMonster function is called periodically.
To do so, add a comma after addMonster and add this new method:
gameLogic:function(dt) {
this.addMonster();
}
Then add this line to the end of onEnter:
this.schedule(this.gameLogic, 3);
This schedules your gameLogic method to spawn a monster every three seconds.
Save your file and refresh your web browser, and you should now have monsters flying across the screen!
Shooting Projectiles
At this point, the ninja is just begging for some action – so let’s add shooting! There are many ways you could implement shooting, but for this game you are going to make it so when the user taps the screen, it shoots a projectile from the player in the direction of the tap.
I want to use a cc.MoveTo action to implement this to keep things at a beginner level, but in order to use this you have to do a little math. This is because the cc.MoveTo requires you to give a destination for the projectile, but you can’t just use the touch point because the touch point represents just the direction to shoot relative to the player. You actually want to keep the bullet moving through the touch point until the bullet goes off-screen.
Here’s a picture that illustrates the matter:
So as you can see, you have a small triangle created by the x and y offset from the origin point to the touch point. You just need to make a big triangle with the same ratio – and you know you want one of the endpoints to be off the screen.
Ok, so onto the code. First, add a new array for the projectiles at the top of the file:
_projectiles:[],
Then you have to enable touches on your layer – but how to handle that depends if your game is being run on a mobile, desktop, or browser device. So add the following code to the beginning of onEnter, right after the call to this._super():
if( 'touches' in sys.capabilities ) {
this.setTouchEnabled(true);
}
if( 'mouse' in sys.capabilities ) {
this.setMouseEnabled(true);
}
This registers the onMouse callbacks to be called if there’s mouse input, or the onTouch methods to be called if there’s touch input.
Then add a comma after gameLogic method, and add these new methods:
locationTapped:function(location) {
// Set up initial location of the projectile
var projectile = cc.Sprite.create(s_projectile);
projectile.setPosition(20, winSize.height/2);
// Determine offset of location to projectile
var offset = cc.pSub(location, projectile.getPosition()); // 1
// Bail out if you are shooting down or backwards
if (offset.x <= 0) return;
// Ok to add now - we've double checked position
this.addChild(projectile);
// Figure out final destination of projectile
var realX = winSize.width + (projectile.getContentSize().width / 2);
var ratio = offset.y / offset.x;
var realY = (realX * ratio) + projectile.getPosition().y;
var realDest = cc.p(realX, realY);
// Determine the length of how far you're shooting
var offset = cc.pSub(realDest, projectile.getPosition());
var length = cc.pLength(offset);
var velocity = 480.0;
var realMoveDuration = length / velocity;
// Move projectile to actual endpoint
projectile.runAction(cc.Sequence.create( // 2
cc.MoveTo.create(realMoveDuration, realDest),
cc.CallFunc.create(function(node) {
cc.ArrayRemoveObject(this._projectiles, node);
node.removeFromParent();
}, this)
));
// Add to array
projectile.setTag(2);
this._projectiles.push(projectile);
},
onMouseUp:function (event) {
var location = event.getLocation();
this.locationTapped(location);
},
onTouchesEnded:function (touches, event) {
if (touches.length <= 0)
return;
var touch = touches[0];
var location = touch.getLocation();
this.locationTapped(location);
}
Again, I'd like to split the explanation here based on whether you're familiar with Cocos2D-iOS already or not.
[spoiler title="I'm Familiar with Cocos2D-iOS"]
Here are some things to point out for those transitioning to Cocos2D-Javascript from Cocos2D-iOS:
- The helper methods to perform math on points that you know and love like ccpAdd, ccpSub are still here - they're just named slightly differently. cc.pSub is the equivalent of ccpSub for example.
- You can create actions in a handy chain just like you can in Cocos2D-iOS.
[/spoiler]
[spoiler title="I'm Completely New to Cocos2D"]
The onMouseUp and onTouchesEnded methods get the location of the mouse click/touch and forward it on to locationTapped.
The beginning of this method loads up the projectile sprite and sets the initial position as usual. You then determine where you wish to move the projectile to, using the vector between the player and the touch as a guide, according to the algorithm described previously.
Note that the algorithm isn’t ideal. You’re forcing the bullet to keep moving until it reaches the offscreen X position – even if you would have gone offscreen in the Y position first! There are various ways to address this including checking for the shortest length to go offscreen, having your game logic callback check for offscreen projectiles and removing rather than using the callback method, etc. but for this beginner tutorial you’ll keep it as-is.
The last thing you have to do is determine the duration for the movement. You want the bullet to be shot at a constant rate despite the direction of the shot, so again you have to do a little math. You can figure out how far you’re moving by using the handy cc.pLength function.
Once you have the distance, you just divide that by the velocity in order to get the duration. This is because velocity = distance over time, or in other words time = distance over velocity.
The rest is setting the actions just like you did for the targets.
[/spoiler]
And that's it - save the file and refresh your browser, and now your ninja should be able to fire away at the oncoming hordes!
Collision Detection
So now you have shurikens flying everywhere – but what your ninja really wants to do is to lay some smack down. So let’s add in some code to detect when your projectiles intersect your targets.
There are various ways to solve this with Cocos2D, including using one of the included physics libraries: Box2D or Chipmunk. However to keep things simple, you are going to implement simple collision detection yourself.
You already have been keeping track of the monsters and projectiles in arrays. All you need to do is periodically check to see if any of them are colliding.
To do this, add a comma after onTouchesEnded and add this new method:
update:function (dt) {
for (var i = 0; i < this._projectiles.length; i++) {
var projectile = this._projectiles[i];
for (var j = 0; j < this._monsters.length; j++) {
var monster = this._monsters[j];
var projectileRect = projectile.getBoundingBox();
var monsterRect = monster.getBoundingBox();
if (cc.rectIntersectsRect(projectileRect, monsterRect)) {
cc.log("collision!");
cc.ArrayRemoveObject(this._projectiles, projectile);
projectile.removeFromParent();
cc.ArrayRemoveObject(this._monsters, monster);
monster.removeFromParent();
}
}
}
}
The above should be pretty clear. You just iterate through your projectiles and monsters, creating rectangles corresponding to their bounding boxes, and use CGRectIntersectsRect to check for intersections. If any are found, you remove them from the scene and from the arrays.
Note that you don't have to create separate "toDelete" arrays like you do in Objective-C, because it's safe to remove elements from an array while iterating through in Javascript.
You just need one more thing before you’re ready to roll – schedule this method to run as often as possible by adding the following line to your onEnter method:
this.scheduleUpdate();
Save the file and refresh your browser, and now when your projectiles intersect targets they should disappear!
Gratuitious Music and Sound Effects
You’re pretty close to having a workable (but extremely simple) game now. You just need to add some sound effects and music (since what kind of game doesn’t have sound!) and some simple game logic.
First, update Cocos2DSimpleGame\Src\resource.js to add the sound effects:
var dirArt = "Art/";
var dirSounds = "Sounds/";
var s_player = dirArt + "player.png";
var s_monster = dirArt + "monster.png";
var s_projectile = dirArt + "projectile.png";
var s_bgMusic = dirSounds + "background-music.mp3";
var s_bgMusicOgg = dirSounds + "background-music.ogg";
var s_bgMusicCaf = dirSounds + "background-music.caf";
var s_shootEffect = dirSounds + "pew-pew-lei.mp3";
var s_shootEffectOgg = dirSounds + "pew-pew-lei.ogg";
var s_shootEffectWav = dirSounds + "pew-pew-lei.wav";
var g_ressources = [
{type:"image", src:s_player},
{type:"image", src:s_monster},
{type:"image", src:s_projectile},
{type:"sound", src:s_bgMusic},
{type:"sound", src:s_bgMusicOgg},
{type:"sound", src:s_bgMusicCaf},
{type:"sound", src:s_shootEffect},
{type:"sound", src:s_shootEffectOgg},
{type:"sound", src:s_shootEffectWav}
];
Note that both the background music and sound effects are each saved in three different formats: mp3, ogg, and wav. This is because not all browsers support all formats, so by adding all three we will have the highest possible chance of the player being able to hear something. Cocos2D will detect what the browser supports and use the appropriate file - as long as they have the same filename.
Note: If you're wondering how to convert between these formats, here's what I do:
- I usually start with a WAV.
- I then use iTunes to convert to an MP3. To do this, go to iTunes Preferences\General\Import Settings and change Import Using to MP3 Encoder. Then you can import a WAV into iTunes, and right click it and select Create MP3 Version to create a MP3.
- I then convert the MP3 to an OGG using oggenc. I used this guide as a howto for installing it.
Now, time to play these effects. Back in Cocos2DSimpleGame\Src\MainLayer.js add this to the top of the file:
var audioEngine = cc.AudioEngine.getInstance();
This gets a global reference to the audio engine so you can use it later. Then add this line to the end of onEnter:
audioEngine.playMusic(s_bgMusic, true);
And add this to the end of locationTapped:
audioEngine.playEffect(s_shootEffect);
Save the file and refresh your browser, and now you should have some groovy tunes!
Winning and Losing
To wrap up, let's create a new scene and layer that will serve as your “You Win” or “You Lose” indicator. Create a new file Cocos2DSimpleGame\Src\GameOver.js and replace the contents with the following:
var GameOver = cc.LayerColor.extend({
_won:false,
ctor:function() {
this._super();
cc.associateWithNative( this, cc.LayerColor );
},
onEnter:function () {
this._super();
var director = cc.Director.getInstance();
var winSize = director.getWinSize();
var centerPos = cc.p( winSize.width/2, winSize.height/2 );
var message;
if (this._won) {
message = "You Won!";
} else {
message = "You Lose :[";
}
var label = cc.LabelTTF.create(message, "Arial", 32);
label.setColor(cc.c3b(0, 0, 0));
label.setPosition(winSize.width/2, winSize.height/2);
this.addChild(label);
this.runAction(cc.Sequence.create(
cc.DelayTime.create(3),
cc.CallFunc.create(function(node) {
var scene = MainLayer.scene();
cc.Director.getInstance().replaceScene(scene);
}, this)
));
}
});
GameOver.create = function (won) {
var sg = new GameOver();
sg._won = won;
if (sg && sg.init(cc.c4b(255, 255, 255, 255))) {
return sg;
}
return null;
};
GameOver.scene = function (won) {
var scene = cc.Scene.create();
var layer = GameOver.create(won);
scene.addChild(layer);
return scene;
};
This is a layer that contains a label in the middle of the screen (cc.LabelTTF) that contains the message. An action is created to wait three seconds, and then transition back to the MainLayer.
To use this new scene, go back to Cocos2DSimpleGame\Src\MainLayer.js and make these changes:
// Add this new instance variable to the top of the file
_monstersDestroyed:0,
// Add inside update, right after monster.removeFromParent():
this._monstersDestroyed++;
if (this._monstersDestroyed >= 2) {
var scene = GameOver.scene(true);
cc.Director.getInstance().replaceScene(scene);
}
// Add inside addMonster, right after node.removeFromParent():
var scene = GameOver.scene(false);
cc.Director.getInstance().replaceScene(scene);
Finally, since you added a new file you need to reference it in cocos2d.js. So open Cocos2DSimpleGame\cocos2d.js and modify the appFiles array to the following:
appFiles:[
'./Src/resource.js',
'./Src/MainLayer.js',
'./Src/GameOver.js',
'./Src/main.js'
]
And that's it! Save the file and refresh your browser, and now you now have a complete Cocos2D Javascript game!
Just One More Thing...
The whole point of Cocos2D-Javascript is that it's cross-platform, right?
Let me show you how you can get this same code running on the iPhone in less than 5 minutes :]
Well - assuming you have the latest version of Cocos2D-iOS already installed that is. If not, download the latest unsable 2.X version (2.1-rc0a) and install the templates.
Note: After downloading the latest version of Cocos2D you can install the templates by running the following commands from a Terminal:
cd ~/Downloads/cocos2d-iphone-2.1-rc0
./install-templates.sh -f -u
Then create a new project in Xcode using the iOS\cocos2d v2.x\cocos2d iOS with JavaScript template. Name the new project Cocos2DSimpleGame and save it in the Cocos2DSimpleGame\Platform\iOS folder.
Then, inside Finder find your Cocos2DSimpleGame folder, select the Art, Sounds, and Src folders, and drag them into your Xcode project. Important: In the popup that appears, select Create folder references for any added folders, and set the rest of the options like the screenshot below:
If you did it correctly, your folders should be blue in Xcode like the screenshot below. If they are yellow, you selected "groups" instead - remove them and try again.
Next, open Resources\main.js and replace the contents with the following:
require("jsb.js");
require("Src/resource.js");
require("Src/MainLayer.js");
require("Src/GameOver.js");
director = cc.Director.getInstance();
winSize = director.getWinSize();
centerPos = cc.p( winSize.width/2, winSize.height/2 );
function run()
{
director.runWithScene( MainLayer.scene() );
}
run();
Here you load your game files, set up the global variables, and run the main scene.
And that's it! Build and run, and now you have the same code running on your iPhone - but using native Cocso2D-iPhone!
Note: Note that if anything is wrong with your Javascript code, sometimes you'll see an error in the Xcode console, but many times default Xcode will give you no useful error messages at all.
This is one of the reasons I find developing initially with Cocos2D-HTML5 much easier.
Where To Go From Here?
Here is a sample project with all of the code from the tutorial so far.
At this point, you have a simple example of a game working with Cocos2D Javascript bindings. If you want to try your hand at making a game of your own, here are some great references:
- Cocos2D and Javascript Overview and FAQ
- Cocos2D Javascript Bindings Implementation and Creating Your Own Bindings
- Cocos2D Javascript API Docs
In addition, stay tuned for part 2 of this tutorial, where you'll learn how to prepare this game for distribution to the web, and create the Mac and Android versions of the game!