Cocos2d-x HTML v2.1: How to migrate from v2.0


I've been getting to know cocos2d-x HTML5 edition for the last few weeks as I try to port one of my mobile applications to HTML5/JS (Pocket Bombs). So far I have had a positive experience with the HTML5 port of the framework (Barring the usual JavaScript annoyances, of course).

A new version of the framework was released a couple days ago (v2.1). This new edition does NOT preserve the same API as the previous version (v2.0). This article explains what I had to do to get my v2 project working with the v2.1 framework.

References:

  • cocos2d-x v2.1 announcement [cocos2d-x.org] (HTML5 download link is further down on the page)
  • HelloHTML5World Sample Project [Found in the ZIP file that contains v2.1 of cocos2d-x html5]
  • samples/tests/index.html sample project [Found in the ZIP file that contains v2.1 of cocos2d-x html5]

 

Overview of changes

Before we get into the details, here's a high-level summary of what files will need to be changed in your project to migrate from v2.0 to v2.1 of cocos2d-x html5:

  • cocos2d.js
  • main.js
  • Any UI Code that uses toggle buttons 

 

 

Changes to cocos2d.js

The cocos2d.js file lives in the same folder as your main index.html file. Here are the changes that I had to make to get this file to work.

Change 1

Change var c to include a couple new items (This is the configuration cocos2d-x uses). New items are bolded

From:

    var c = {
        COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug
        box2d:false,
        showFPS:true,
        frameRate:60,
        tag:'gameCanvas', //the dom element to run cocos2d on
        //engineDir:'../cocos2d/',
        engineDir: '../Cocos2d-html5-v2.0/cocos2d/',
        appFiles:['Classes/PB.Initialize.js', 'UI/Game/PB.UI.Game.Default.js']
    };

To:

    var c = {
        COCOS2D_DEBUG:2, //0 to turn debug off, 1 for basic debug, and 2 for full debug
        box2d:false,
        chipmunk:false,
        loadExtension:false,
        showFPS:true,
        frameRate:60,
        tag:'gameCanvas', //the dom element to run cocos2d on
        //engineDir:'../cocos2d/',
        engineDir: '../Cocos2d-html5-v2.1/cocos2d/',
        appFiles:['Classes/PB.Initialize.js', 'UI/Game/PB.UI.Game.Default.js']
    };

 

Change 2

Replace the window.addEventListener('DOMContentLoaded', function () with the new one provided in the HelloHTML5World sample

From:

    window.addEventListener('DOMContentLoaded', function () {
        //first load engine file if specified
        var s = d.createElement('script');
        s.src = c.engineDir + 'platform/jsloader.js';
        d.body.appendChild(s);
        s.c = c;
        s.id = 'cocos2d-html5';
    });

To:

    window.addEventListener('DOMContentLoaded', function () {
        //first load engine file if specified
        var s = d.createElement('script');
        /*********Delete this section if you have packed all files into one*******/
        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"');
        }
        /*********Delete this section if you have packed all files into one*******/

            //s.src = 'Packed_Release_File.js'; //IMPORTANT: Un-comment this line if you have packed all files into one

        document.ccConfig = c;
        s.id = 'cocos2d-html5';
        d.body.appendChild(s);
        //else if single file specified, load singlefile
    });

 

 

Changes to main.js

The main.js file lives in the same folder as your index.html file. Here are the changes that I had to make to get this file to work. I've highlighted the changes below in bold to make it easier to see what needs to be changed.

In a Nutshell, cc.Loader.shareLoader() changed to cc.Loader.getInstance() and cc.LoaderScene.shareLoaderScene() changed to cc.LoaderScene.getInstance()

From:

var cocos2dApp = cc.Application.extend({
    config:document.querySelector('#cocos2d-html5')['c'],
    ctor:function (scene) {                                             // Accepts a Scene for runnning
        this._super();
        this.startScene = scene;
        cc.COCOS2D_DEBUG = this.config['COCOS2D_DEBUG'];
        cc.setup(this.config['tag']);
        cc.Loader.shareLoader().onloading = function () {
            cc.LoaderScene.shareLoaderScene().draw();
        };
        cc.Loader.shareLoader().onload = function () {
            cc.AppController.shareAppController().didFinishLaunchingWithOptions();
        };
        cc.Loader.shareLoader().preload([
            {type:"plist",src:"Themes/spritesheet1.plist"},
            {type:"plist",src:"Themes/spritesheet2.plist"}
        ]);
    },
    applicationDidFinishLaunching:function () { // This function launches your code
        var director = cc.Director.getInstance();
        director.setDisplayStats(this.config['showFPS']);
        director.setAnimationInterval(1.0 / this.config['frameRate']);
        director.runWithScene(new this.startScene());
        return true;
    }
});

To:

var cocos2dApp = cc.Application.extend({
    config:document['ccConfig'],
    ctor:function (scene) {                          // Accepts a Scene for runnning
        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([
            {type:"plist",src:"Themes/spritesheet1.plist"},
            {type:"plist",src:"Themes/spritesheet2.plist"}
        ]);
    },
    applicationDidFinishLaunching:function () { // This function launches your code
        var director = cc.Director.getInstance();
        director.setDisplayStats(this.config['showFPS']);
        director.setAnimationInterval(1.0 / this.config['frameRate']);
        director.runWithScene(new this.startScene());
        return true;
    }
});

 

 

Changes to Your UI Code

This is the fun part. Now that your program can get to the point of loading in a web browser you'll probably see a bunch of errors like Assertion failed: child already added. It can't be added again or something like that.

I found a couple of APIs had changed for the Menu system and I had to change all instances of my old usage to the new system. The specific APIs that have changed (that I have been able to identify) are:

  • cc.MenuItemFont.create
  • cc.MenuItemToggle.create

 

Change to cc.MenuItemFont.create

For Clarity I have bolded the changes in the v2.1 API.

Before (v2.0):

var newGameBtn = new cc.MenuItemFont.create("New Game", this, this.newGame);

Now (v2.1):

var newGameBtn = cc.MenuItemFont.create("New Game", this.newGame, this);

Comments:

This change involved flipping the last 2 arguments of the create API to include the callback function first

 

Change to cc.MenuItemToggle.create

For Clarity I have bolded the changes in the v2.1 API.

Before (v2.0):

var bToggle = cc.MenuItemToggle.create(this,this.toggle, cc.MenuItemFont.create("4"), cc.MenuItemFont.create("5"));

Now (v2.1):

var bToggle = cc.MenuItemToggle.create(cc.MenuItemFont.create("4"), cc.MenuItemFont.create("5"));
bToggle.setCallback(this.toggleBoardSizeX, this);

Comments:

With this one we now have to add the callback information in a new API call setCallback().

 

 

Final Thoughts

While the changes between v2.0 and 2.1 are fairly small, it is a hassle to have to go back through all your API calls to match the new syntax. Hopefully cocos2d-x html5 will continue to stabilize its API over time. I wasn't expecting any changes in a point release! :)

With that said, I think the guys who maintain cocos2d-x have done a great job. The framework is solid and is meeting my needs. Thanks!