Cocos2d-js box2d debug draw ARRRGH!

Hi,

I am getting REALLY frustrated trying to get debug draw working with Box2d in cocos2d-js.

Does a unit test or example that’s up to date exist???

I have read many many posts and they suggest having a separate canvas just for the debug box2d or setting up a another cc-node etc as a layer. These seem to be old posts.

Without going into everything that I have tried to do that hasn’t worked, and in all honesty before I throw in the cards and pay money for another game engine (i.e. construct 2D) can anyone help ??? It seems I post things on here and very infrequently will someone be willing or able to answer which makes me think that getting an engine where they employ support staff would be a better idea for my business.

Right now I’m just fed up with how hard it is to resolve in cocos2d what seem like simple things to do in other engines.

I cannot get it working either in C++

Compiles fine but nothing shows up

I am using files made by Amim , my post is here

So far, I think the renderMode needs to be “canvas” or 1 in the project.json file for it to not crash but nothing shows up. I don’t know if this has any bearing on your project.

Just follow box2d guide for that. Only took about 15 mins for it to get working properly (once you realize that coordinates need to be flipped). Don’t give up. Good luck.

Hi, thanks for reply. Where do I look?

Search feature of this forum is a good start.

Yes did that for 4 hours. Forum helped but I couldn’t get it working. Box2d.js worked with html but not DebugDraw. What would you suggest?

Well, here’s a bit of code I came up with. Works like a charm.

_enableDebugDraw: function(){
        var oldDebugDrawCanvas = document.getElementById("debugDrawCanvas");
        if(oldDebugDrawCanvas){
            document.getElementById("Cocos2dGameContainer").removeChild(oldDebugDrawCanvas);
        }
        var testCanvas = document.createElement("canvas");
        var styleString = document.getElementById("gameCanvas").style;

        testCanvas.id = 'debugDrawCanvas';
        testCanvas.style.height = styleString.height;
        testCanvas.height = document.getElementById("gameCanvas").height;
        testCanvas.style.width = styleString.width;
        testCanvas.width = document.getElementById("gameCanvas").width;
        testCanvas.style.position = "absolute";
        testCanvas.style.top = "0px";
        testCanvas.style.outline = "none";
        testCanvas.style.left = "0px";
        testCanvas.style["-webkit-transform"] = "rotate(180deg) scale(-1, 1)";
        testCanvas.style["pointer-events"] = "none";
        document.getElementById("Cocos2dGameContainer").appendChild(testCanvas);
        this._debugDraw = new Box2D.Dynamics.b2DebugDraw();
        this._debugDraw.SetSprite(testCanvas.getContext("2d")); // test is the id of another canvas which debugdraw works on
        this._debugDraw.SetDrawScale(document.getElementById("gameCanvas").width / config.appViewport.width * this.PIXELS_TO_METER_RATIO);
        this._debugDraw.SetFillAlpha(0.3);
        this._debugDraw.SetLineThickness(1.0);
        this._debugDraw.SetFlags(b2.DebugDraw.e_shapeBit | b2.DebugDraw.e_jointBit | b2.DebugDraw.e_edgeShape);
        this._world.SetDebugDraw(this._debugDraw);
    },
1 Like

blimey! … it looks interesting what does your html look like?

just regular boilerplate code provided by cocos.

this code creates a canvas on top of existing canvas that runs your game. Then it rotates it in specific way to align coordinates (sorry to spoil this part, it was very interesting to figure out). So a new canvas is used as debugDraw output for my world. Nothing tricky there.

So did there used to be a “debugDrawCanvas” element in the default html somewhere? looks amazing… I will give it a try in the morning.

it is created by this very same function. Please read it carefully and you will see it.
It is done in this way, in case you call this function many times - you don’t want to have copies of it.

I tried it, it’s close but my game is “portrait” and I think the debug canvas is not on top of the gameCanvas. Also debug is not showing up. I don’t know if it’s because I have a layer on the scene with a z-index > 1??

Finally sorted this with your help I had to make some minor changes:

_enableDebugDraw: function(){
    // _world is my Box2d world
    // _worldScale is my PTM ratio used when I setup the world!
    // this._layerName is just for logging and is a local var to this layer
    //
    
    cc.log(this._layerName + '.' + arguments.callee.name);

    var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;

    var oldDebugDrawCanvas = document.getElementById("debugDrawCanvas");
    if(oldDebugDrawCanvas){
        document.getElementById("Cocos2dGameContainer").removeChild(oldDebugDrawCanvas);
    }
    var testCanvas = document.createElement("canvas");
    var styleString = document.getElementById("gameCanvas").style;

    testCanvas.id = 'debugDrawCanvas';
    testCanvas.height = document.getElementById("gameCanvas").height;
    testCanvas.width = document.getElementById("gameCanvas").width;
    testCanvas.style.height = styleString.height;
    testCanvas.style.width = styleString.width;

    testCanvas.style.position = "absolute";
    testCanvas.style.top = "0px";
    testCanvas.style.outline = "none";
    testCanvas.style.left = "0px";
    testCanvas.style.top = document.getElementById('Cocos2dGameContainer').style.paddingTop;
    testCanvas.style["-webkit-transform"] = "rotate(180deg) scale(-1, 1)";
    testCanvas.style["pointer-events"] = "none";
    document.getElementById("Cocos2dGameContainer").appendChild(testCanvas);
    this._debugDraw = new Box2D.Dynamics.b2DebugDraw();
    this._debugDraw.SetSprite(testCanvas.getContext("2d")); // test is the id of another canvas which debugdraw works on
    var scale = this._worldScale * cc.EGLView._getInstance().getViewPortRect().width / cc.EGLView._getInstance().getDesignResolutionSize().width;
    this._debugDraw.SetDrawScale(scale);

    this._debugDraw.SetFillAlpha(0.3);
    this._debugDraw.SetLineThickness(1.0);
    this._debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit | b2DebugDraw.e_edgeShape);
    this._world.SetDebugDraw(this._debugDraw);
},

Then in my update function I have:

update: function (dt) {

    //It is recommended that a fixed time step is used with Box2D for stability
    //of the simulation, however, we are using a variable time step here.
    //You need to make an informed choice, the following URL is useful
    //http://gafferongames.com/game-physics/fix-your-timestep/

    var velocityIterations = 8;
    var positionIterations = 1;

    // Instruct the world to perform a single step of simulation. It is
    // generally best to keep the time step and iterations fixed.

    this._world.Step(dt, velocityIterations, positionIterations);

    //Iterate over the bodies in the physics world
    for (var b = this._world.GetBodyList(); b; b = b.GetNext()) {
        if (b.GetUserData() != null) {
            var point = pr.B2PositionToPoint(b.GetPosition(), this._worldScale);
            var ang = pr.B2AngleToDegrees(b.GetAngle());
            
            var mySprite = b.GetUserData().asset;
            mySprite.setPosition(point);
            mySprite.setRotation(ang);
        }
    }
    this._world.DrawDebugData();
    this._world.ClearForces();
},

I will contact you privately if that’s OK as I would like to buy you a beer or more for your help!! :slight_smile:

Here is my final code, I made some changes to tidy it up a bit:

_enableDebugDraw: function(){
    cc.log(this._layerName + '.' + arguments.callee.name);

    var oldDebugDrawCanvas = document.getElementById("debugDrawCanvas");
    if(oldDebugDrawCanvas){
        document.getElementById("Cocos2dGameContainer").removeChild(oldDebugDrawCanvas);
    }

    var scale = this._worldScale * cc.EGLView._getInstance().getViewPortRect().width 
        / cc.EGLView._getInstance().getDesignResolutionSize().width;

    var gameCanvas = document.getElementById("gameCanvas");
    var gameContainer = document.getElementById("Cocos2dGameContainer");

    var testCanvas = document.createElement("canvas");
    testCanvas.id = 'debugDrawCanvas';
    testCanvas.height = gameCanvas.height;
    testCanvas.width = gameCanvas.width;
    testCanvas.style.height = gameCanvas.style.height;
    testCanvas.style.width = gameCanvas.style.width;
    testCanvas.style.position = "absolute";
    testCanvas.style.outline = "none";
    testCanvas.style.left = "0px";
    testCanvas.style.top = gameContainer.style.paddingTop;
    testCanvas.style["-webkit-transform"] = "rotate(180deg) scale(-1, 1)";
    testCanvas.style["pointer-events"] = "none";
    gameContainer.appendChild(testCanvas);

    // testCanvas is the id of another canvas which debugdraw works on
    this._debugDraw = new Box2D.Dynamics.b2DebugDraw();
    this._debugDraw.SetSprite(testCanvas.getContext("2d")); 
    this._debugDraw.SetDrawScale(scale);
    this._debugDraw.SetFillAlpha(0.3);
    this._debugDraw.SetLineThickness(1.0);

    var b2DebugDraw = Box2D.Dynamics.b2DebugDraw;
    this._debugDraw.SetFlags(b2DebugDraw.e_shapeBit
         | b2DebugDraw.e_jointBit | b2DebugDraw.e_edgeShape);

    this._world.SetDebugDraw(this._debugDraw);
},

Good thing it worked!

P.S. I’ll never say no to a beer :slight_smile:

1 Like

I got it working. I figured out the flipping coordinate thing and also just need understand this meter to pixel thing