How To Make a Cross-Platform Game with Cocos2D Javascript Tutorial: Getting Started

Ray Wenderlich

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

Cocos2D Javascript Bindings

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?

Cocos2D-HTML5So 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:

Starter Project Directory Structure

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:

  1. 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.
  2. Creates a constructor for the class, that calls the superclass’s constructor.
  3. 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.
  4. 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.
  5. 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.
  6. Sets the position of the sprite to be the middle-left of the screen. winSize is a handy constant you will define later.
  7. 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.

  1. The first is a helper method to create a new instance of the MainLayer.
  2. 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:

Preparing your directory structure for your Cocos2D-HTML5 project

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.

  1. These are various Cocos2D settings, such as the debug level for the framework and which libraries to enable (Box2D, etc).
  2. 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.
  3. 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:

  1. Initializes those global helper variables I mentioned earlier.
  2. 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!

Hello World HTML5-Javascript!

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.

Solution Inside: I'm Familiar with Cocos2D-iOS SelectShow
Solution Inside: I'm Completely New to Cocos2D SelectShow

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!

Spawning Monsters

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:

Projectile Triangle

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.

Solution Inside: I'm Familiar with Cocos2D-iOS SelectShow
Solution Inside: I'm Completely New to Cocos2D SelectShow

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!

Shooting Projectiles

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!

You won!

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:

Adding folders to your Xcode project

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.

Make sure the folders are blue

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!

Cocos2D Javascript project running on 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:

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!

Ray Wenderlich

Ray is an indie software developer currently focusing on iPhone and iPad development, and the administrator of this site. He’s the founder of a small iPhone development studio called Razeware, and is passionate both about making apps and teaching others the techniques to make them.

When Ray’s not programming, he’s probably playing video games, role playing games, or board games.

User Comments

26 Comments

[ 1 , 2 ]
  • Hi Ray, the tutorial is great! Just a little issue, I grabbed latest cocos2d version v2.1-rc1 and followed all steps, but the app crashes with this message:

    Code: Select all
    2013-04-26 17:36:41.381 xxxxxxxxx[8343:15203] *** Assertion failure in void JSB_set_proxy_for_jsobject(void *, JSObject *)(), /Users/xxxxxx/Desktop/xxxxxxx/Platform/iOS/xxxxxxx/xxxxxxx/libs/jsbindings/src/manual/jsb_core.mm:637
    2013-04-26 17:36:41.382 xxxxxxxxxx[8343:15203] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Already added. abort'


    When I run your demo (v2.1-rc0a) works fine.

    Thanks.
    jmgomezg
  • Hey there,

    This is a great framework and I've been playing with it for a while now. One thing I would love to know is how to implement saving and loading to games/apps written in this way. At the moment I have a couple of games that all reset every time I exit which kind of spoils the fun. A tutorial or hints on how to save files either locally or on a webserver/ database from the javascript would be great : )

    thank you...

    Edit:

    Had someone point me in the direction of system.localstorage for saving locally which I completely overlooked and seems to do what I want (not checked with the IPhone port yet)..

    As a web option: Including JQuery in the list of loaded JS files in the Cocos2d.js file and then doing a standard AJAX call, works well but I imagine will fall to as many pieces as soon as I port to any mobile platforms.

    If anyone has any ideas how to do this within the framework that might work for the Iphone port that would be great : )

    thx
    thatguy
  • Hi,

    Thanks for the tutorial.

    I am currently trying to get the first bit running. I have the latest version of Cocos2d-HTML5 (2.1.4), and I think some of the APIs have changed, though. In particular, the CC.Loader inside of main.js

    In the code there is

    Code: Select all

    cc.Loader.getInstance().preload(g_ressources);


    but I believe it should be

    Code: Select all

    cc.Loader.preload(g_ressources, STRING_SELECTOR, target);


    At least, per http://www.cocos2d-x.org/reference/html5-js/symbols/cc.Loader.html#.preload

    What is not clear is exactly how to use this function. I am still looking for a quick example to know what to pass as selector and target.

    SOLVED

    Here is the updated main.js

    Basically, I moved the preload to upon application finish loading. I also ensured we call

    Code: Select all

    cc.AppController.shareAppController().didFinishLaunchingWithOptions();


    I suspect my solution is materially different in that we are preloading after application is up, but for now at least I have things displaying as desired. :)

    Code: Select all

    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.AppController.shareAppController().didFinishLaunchingWithOptions();
        },
        applicationDidFinishLaunching:function () {
           
            director = cc.Director.getInstance();
           
            director.setDisplayStats(this.config['showFPS']);
            director.setAnimationInterval(1.0 / this.config['frameRate']);
           
            // 1
            winSize   = director.getWinSize();
            centerPos = cc.p( winSize.width/2, winSize.height/2 );
           
            //load resources
            cc.Loader.preload(g_resources, function () {
                cc.Director.getInstance().runWithScene(new this.startScene());
            }, this);
           
            // director.runWithScene(new this.startScene());
            return true;
        }
    });

    // 2
    var director;
    var winSize;
    var centerPos;
    var myApp = new cocos2dApp(MainLayer.scene);
    wwvuillemot
  • I knew the cocos2d-html5 version. I wonder if this version can make games as Facebook apps?

    I look forward to your answers!
    thanhvinh1
  • Well, i found this tutorial very helpful but i am getting

    Cocos2d-html5-v2.1.5 CCCommon.js:145
    Assertion failed: CCApplication ctor CCCommon.js:168
    cc.Assert CCCommon.js:168
    cc.Application.cc.Class.extend.ctor CCApplication.js:307
    cc.Application.extend.ctor main.js:4
    (anonymous function) CCClass.js:136
    (anonymous function)
    (anonymous function) main.js:38
    Cocos2d-html5-v2.1.5 CCCommon.js:145

    This error as i am new to this i can only understand that this is problem within main.js .
    Found there two links related to this error but don't know how to make my code run.

    http://www.cocos2d-x.org/boards/19/topics/25845
    http://www.cocos2d-x.org/boards/19/topics/29547

    Can you help??
    matrixhooda
  • I have an error
    "ReferenceError: document is not defined in main.js"

    The first steps are not that clear for me.
    I am using cocosino to create my first cocos2d-x game
    Neiphone
  • I import it as an iPhone project. But after i won once. I got this error message from the other trying:

    jsb: ERROR in JSB_CCNode_boundingBox: Invalid Proxy object

    And i could not catch the collision.
    hacy
  • I visited http://www.cocos2d-iphone.org/download/ and download Cocos2D-v3.0.0.rc , but when I try to create new project in XCode I don't see javascript template. Could you help me about this? Thanks
    phucpham
  • may God bless you
    harsh410
  • I developed the game in Cocos2dJs recently, Published a Book on Cocos2dJs

    Cocos2d-Js Mobile Game Development on Steroids.

    My game TINYRUN is available right now on Google Play.

    Also the source code for the game is available along with the book.
    shreedharcva
  • I ported your source for v2.2.3.
    If you like, I open public via bitbucket.
    shinriyo
[ 1 , 2 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Vote for Our Next Tutorial!

Every week, we alternate between Gaming and Non-Gaming tutorial votes. This week: Gaming!

    Thank you for voting! :]

    Total Voters: 820

    Loading ... Loading ...

Last week's winner: Apple TestFlight Tutorial.

Suggest a Tutorial - Past Results

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in January: WatchKit.

Sign Up - January

Our Books

Our Team

Tutorial Team

  • Ernesto García

... 60 total!

Update Team

  • Ray Fix

... 12 total!

Editorial Team

  • John Clem

... 17 total!

Code Team

  • Orta Therox

... 3 total!

Subject Matter Experts

... 4 total!