Search code examples
androidhtmlperformancegame-physicsbox2dweb

Is it a big difference to use Box2D in native Android game instead of Box2Dweb with HTML5 canvas?


I have to write a simulation of balls falling in a container for Android. First, I tried using Box2Dweb in a HTML5 canvas, but with 3 solid bodies and 50 balls, it performs really slow, even in desktop computer with Firefox (curiously, with Chrome it performs really well). Here is the live demo.

And here is the code.

     var    b2Vec2 = Box2D.Common.Math.b2Vec2
        ,   b2BodyDef = Box2D.Dynamics.b2BodyDef
        ,   b2Body = Box2D.Dynamics.b2Body
        ,   b2FixtureDef = Box2D.Dynamics.b2FixtureDef
        ,   b2Fixture = Box2D.Dynamics.b2Fixture
        ,   b2World = Box2D.Dynamics.b2World
        ,   b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
        ,   b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
        ,   b2DebugDraw = Box2D.Dynamics.b2DebugDraw
        ;

     var world = new b2World(
           new b2Vec2(0, 10)    //gravity
        ,  true                 //allow sleep
     );

     var fixDef = new b2FixtureDef;
     fixDef.density = 1.0;
     fixDef.friction = 0.5;
     fixDef.restitution = 0.2;

     var bodyDef = new b2BodyDef;

     //create ground
     var canvas = $('#canvas'),
         offsetX = (canvas.width() / 30) / 4,
         offsetY = (canvas.height() / 30) / 5; //center the machine on the screen.

     bodyDef.type = b2Body.b2_staticBody;
     fixDef.shape = new b2PolygonShape;
     fixDef.shape.SetAsBox(5, 0.5);
     bodyDef.position.Set(5 + offsetX, 10 + offsetY);
     world.CreateBody(bodyDef).CreateFixture(fixDef);
     fixDef.shape.SetAsBox(0.5, 7);
     bodyDef.position.Set(0 + offsetX, 3 + offsetY);
     world.CreateBody(bodyDef).CreateFixture(fixDef);
     bodyDef.position.Set(10 + offsetX, 3 + offsetY);
     world.CreateBody(bodyDef).CreateFixture(fixDef);


     //create some objects
     var numObjects = 50;
     bodyDef.type = b2Body.b2_dynamicBody;
     for(var i = 0; i < numObjects; ++i) {
        fixDef.shape = new b2CircleShape(
            0.6 //Math.random() + 0.1 //radius
        );

        bodyDef.position.x = Math.random() * 9 + offsetX;
        bodyDef.position.y = Math.random() * 9 - 2;
        world.CreateBody(bodyDef).CreateFixture(fixDef);
     }

     //setup debug draw
     var debugDraw = new b2DebugDraw();
        debugDraw.SetSprite(document.getElementById("canvas").getContext("2d"));
        debugDraw.SetDrawScale(30.0);
        debugDraw.SetFillAlpha(0.5);
        debugDraw.SetLineThickness(1.0);
        debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit);
        world.SetDebugDraw(debugDraw);

     var rate = 60;

     window.requestAnimFrame = (function(){
        return window.requestAnimationFrame       ||
               window.webkitRequestAnimationFrame ||
               window.mozRequestAnimationFrame    ||
               function( callback ){
                 window.setTimeout(callback, 1000 / rate);
               };
     })();

     //update         
     (function update() {
        requestAnimFrame(update);
        world.Step(1 / rate, 10, 10);
        world.DrawDebugData();
        world.ClearForces();                        
     })();

My question is, what if I write a native implementation using Android canvas (no the HTML5 one) and Box2D? Will I achieve a smooth movement for the balls?

And the hidden cuestion is: Is the performance so poor because of drawing or because of so many physical calculus? Usually, how much performance can I win going to native when there are physical calculus involved?


Solution

  • The main difference is that with HTML5 and Box2DWeb your game is limited by the browser optimizations and your own code optimizations.

    Some browsers doesn't have hardware accelerated canvas; or the browser's Javascript Engine are not optimized enough. You can see that difference even in desktop browsers. Google Chrome for instance do a lot of optimizations behind the scene inside his V8 engine.

    Because there's so many differences between Browser's Javascript Engines (as you notice with Firefox and Chrome) it's harder to do code optimizations for all of them.

    Since mobile hardware is usually very limited and the mobile browsers are not evolved enough, make optimizations to active high frame rates is very painful and may not be accomplished at all.

    For instance, the code you provide might suffer in browsers that haven't no native requestAnimationFrame. Also, drawing shapes on the fly is too expensive for low hardware devices. So the answer for your last question might be: both, drawing and the physics calculation are killing the performance. But the major bottleneck is the drawing for sure.

    The use of native Android canvas allow you quick responses since the game will use the device hardware more efficiently than browsers.

    In addiction, the Box2D for android is much more efficient than the Box2DWeb(a nice port of the original Box2D but still suffer with performance gaps).

    Bottomline, if your target is primary Android devices you should go with the native implementation. But if you want to target a huge range of browsers and devices without do code again for every platform, go with the beautiful HTML5. (Every choice implies consequences, you have to choose that which best suit your needs).

    If you decide goes with HTML5 canvas see this answer. (It's you own question, by the way :) )

    And if you are really engaged learn a little about WebGL and OpenGL ES.