cocos2d jsbinding javascript code optimize

I’m trying to write an rpg game using cocos2d-html5 + jsbinding (spidermonkey) and here is the performance issue I had while handling the collision detect part.

So I wrote a simple demo with only collision detect code to test the performance and try to find a way optimize the code.

About the demo: 50 robots are keep walking randomly on the map while 50 bullets are flying randomly on the map as well.

engine version: cocos2d-html5 2.2.2 + cocos2d-x 2.2.2

  1. no physical engine used, the collision detect part relies on rect/point intersect detect only (since it’s enough for this game)

  2. sprite classes are derived from cc.sprite in order to use cc.spriteBatchNode


var MapObject = cc.Sprite.extend({
    init:function() {
        if (this.initWithSpriteFrameName("test.png")) {
            this._collisionRect = cc.rect(this.getPositionX() - this.getContentSize().width / 2,
                                       this.getPositionY() - this.getContentSize().height / 2,
                                       this.getContentSize().width,
                                       this.getContentSize().height * 0.2);
            return true;
        }
        return false;
    },
    getCollisionRect:function() {
        return this._collisionRect
    }
});

var BulletObject = MapObject.extend({
    init:function() {
        if (this._super()) {
            return true;
        }
        return false;
    }
});
BulletObject.create = function() {
    var mapObject = new BulletObject();
    if (mapObject && mapObject.init()) {
        return mapObject;
    }
    return null;
};

var RobotObject = MapObject.extend({
    init:function() {
        if (this._super()) {
            return true;
        }
        return false;
    }
});
RobotObject.create = function() {
    var mapObject = new RobotObject();
    if (mapObject && mapObject.init()) {
        return mapObject;
    }
    return null;
};

  1. and a single instance class for handling all objects:
var MapObjectManager = function () {
    this.init = function() {
        this.robotObjectArray = new Array();
        this.bulletObjectArray = new Array();
    },
    this.checkCollision = function() {
    }
};
var sharedMapObjectManager = null;
MapObjectManager.getInstance = function () {
    if (sharedMapObjectManager == null) {
        sharedMapObjectManager = new MapObjectManager();
        sharedMapObjectManager.init();
    }
    return sharedMapObjectManager;
};
  1. the data for test is 50 sprites (as walking robots) and 50 sprites (as flying bullets)
for (var i = 0; i < 50; i++) {
    var mapObject = RobotObject.create();
    MapObjectManager.getInstance().robotObjectArray.push(mapObject);
    this.mapBatch.addChild(mapObject);
}

for (var i = 0; i < 50; i++) {
    var mapObject = BulletObject.create();
    MapObjectManager.getInstance().BulletObjectArray.push(mapObject);
    this.mapBatch.addChild(mapObject);
}
  1. the collision detect is triggered each frame
update:function(dt) {
    MapObjectManager.getInstance().checkCollision();
}

  1. the demo only tests the worst situation in checkCollision:
this.checkCollision = function() {
    for (var i = 0, iLength = this.robotObjectArray.length; i < iLength; i++) {
        var a = this.robotObjectArray[i];
        for (var j = 0, jLength = this.bulletObjectArray.length; j < jLength; j++) {
            var b = this.bulletObjectArray[j];
                    // collision detect code gose here
    }
}
  1. and here is the result of fps on real machine (ipod touch5) for different collision detect code:
     Sprites-A    Sprites-B      FPS         Update
 .      50          50           60         no collision check (empty for-for loop)
a.      50          50           9          if (cc.rectContainsPoint(a.getBoundingBox(), b.getPosition()))
b.      50          50           9          if (cc.rectContainsRect(a.getBoundingBox(), b.getBoundingBox()))
c.      50          50           6          if (cc.rectContainsPoint(cc.rect(a.getPositionX(),
                                                                            a.getPositionY(),
                                                                            a.getContentSize().width,
                                                                            a.getContentSize().height), 
                                                                            b.getPosition()))
d.      50          50           14         if (cc.rectContainsPoint(a.getCollisionRect(), b.getPosition()))
e.      50          50           16         if (cc.rectContainsPoint(a._collisionRect, b.getPosition()))
f.      50          50           19         var p = b.getPosition();
                                            if (p.x >= a._collisionRect.x && 
                                                p.x <= (a._collisionRect.x + a._collisionRect.width) &&
                                                p.y >= a._collisionRect.y && 
                                                p.y <= (a._collisionRect.y + a._collisionRect.height)) {
                                            }
g.      50          50           22         var p = b.getPosition();
                                            var r = a._collisionRect;
                                            if (p.x >= r.x && 
                                                p.x <= (r.x + r.width) &&
                                                p.y >= r.y && 
                                                p.y <= (r.y + r.height)) {
                                            }
h.      50          50           31         var px = b.getPositionX();
                                            var py = b.getPositionY();
                                            var r = a._collisionRect;
                                            if (px >= r.x && 
                                                px <= (r.x + r.width) &&
                                                py >= r.y && 
                                                py <= (r.y + r.height)) {
                                            }
i.      50          50           31         replace for-for loop with while-while loop

Explanation for each situation (50 * 50 sprite – for -for lop – per frame):

. it reaches a stable 60 fps when there is no collision detect code added ~

a. 2500 calculation using – result: very slow

b. change to – result: same as [a]

c. since dose more than returning the bounding rect of the sprite I try to create the bounding box using and – result: get worse

d. I try to store the bounding box in a property at init time and than use it in loop (get function) – result: better (this might not work in the real game since the bounding box is change each frame since all the robots and bullets are moving per frame, but this is for test)

e. still use the stored bounding rect but directly through property – result: better

f. implement the function directly instead of function calling and store result of locally – result: better

g. reduce <._collisionRect> property access by storing it in local variable – result: better

h. reduce property access by storing them in local variable – result: great

As you can see that the best fps now I can get is only 30 fps and there is what I am eager to know:
is there anything I can do to raise the fps such as reduce function calling in for loop (60 fps is the final goal for a test like this :slight_smile: )

Any suggestion will be appreciated, thanks :slight_smile:

Hi,

I think the problem here is that you used JS to do all the calculation of collision. And that is very slow in JSB.
I suggest you to do it with C++, JS only calls the APIs, it will be much better.