Box2d debug draw with coco2d

Hi all,
I have problems drawing a box. I’m using coco2d + box2d (latest versions) in c++. Anyone know how can I view exactly the box that box2d is drawing? if I declare this:

b2PolygonShape bps; 
bps.SetAsBox(2/SCALE_RATIO, 2/SCALE_RATIO);

When another object collides with the box, I have some idea that limits of the box. But how can I view in the screen the 4 lines box that box2d is drawing?

I read about GLES-Render for debug drawing. This should help me? I tried follow this steps:

  1. I downloaded this file: http://discuss.cocos2d-x.org/uploads/default/12747/1d511bac2a477efb.zip

  2. I added the .h and .cpp files to my project.

  3. I added this method to my Scene class:

    void GameManager::draw(Renderer renderer, const Mat4 &transform, uint32_t flags)
    {
    GL::enableVertexAttribs( GL::VERTEX_ATTRIB_FLAG_POSITION );
    Director
    director = Director::getInstance();
    CCASSERT(nullptr != director, “Director is null when seting matrix stack”);
    director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    world->DrawDebugData();
    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    }

  4. In my GameManager class, in the Constructor, when I create the scene, I added:

scene->addChild(B2DebugDrawLayer::create(_world, SCALE_RATIO), 99);

After that, I run the program and it’s not compile. It failed with 2 errors:

Apple Mach-O Linker (ld) Error Group
"B2DebugDrawLayer::create(b2World*, float)", referenced from:
clang: error: linker command failed with exit code 1 (use -v to see invocation)

I tested another GLES-Render classes and some compiles work fine but I don’t view the 4 box line that box2d is drawing. Anyone have any example that works in the last versions? Adding the layer child should be sufficient ? or I should be edit other part of my code?

Thanks

Hello

Man, currently I’m working a fully wrapping for box2d with cocos2dx

It’s has similar api for built in physics

Currently my api has the following

1- world creation
2- body creation even from a sprite bounding box
3- smart collision no need to mass if statements for simple collision
4- all joins
5- debug the world with bodies

But i have to put last touches on it

I need few days to finish it

You will find very useful for u

Believe it’s will worth the waiting

Contact me if you want become tester
Best regards

see


for a post of the stuff I use - it may be helpful

@xCode_Soul thanks! When you finish your code, please share it in this topic!
@Maxxx I tried to use your code. I adapted the code to my game. This is the code that I’m using:

file .h:

#ifndef __DebugLayer_H_
#define __DebugLayer_H_
#include "GLES-Render.h"

class DebugLayer : public cocos2d::Layer
{
private:
    GLESDebugDraw* _debugDraw;
    b2World *w;
    
public:

    virtual bool init();
    DebugLayer(b2World*);
    ~DebugLayer();
    virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4& transform, uint32_t flags);
};

#endif //__DebugLayer_H_

file .cpp:

#include "DebugLayer.h"
USING_NS_CC;

bool DebugLayer::init()
{
    if (!Layer::init())
    {
        return false;
    }
    
    // set up box2d ratio and debug flags
    _debugDraw = new GLESDebugDraw(32);
    w->SetDebugDraw(_debugDraw);
    uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
    //	flags += b2Draw::e_jointBit;
    //	flags += b2Draw::e_centerOfMassBit;
    //  flags += b2Draw::e_aabbBit;
    //	flags += b2Draw::e_pairBit;
    _debugDraw->SetFlags(flags);
    
    return true;
}

void DebugLayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
{
    cocos2d::Layer::draw(renderer, transform, flags);
    
    GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION);
    Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    w->DrawDebugData();
    
    Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
    
}

DebugLayer::DebugLayer(b2World *world)
{
    w = world;
    init();
}

DebugLayer::~DebugLayer()
{
    delete _debugDraw;
}

And in the method that I create the gameScene and world, I added this lines:

DebugLayer *debugLayer = new DebugLayer(world);
gameScene->addChild(debugLayer);

When I compile the game I see the drawings but these are in another place, not exactly where the sprites are. Do you understand me? For example, if I have a sprite box in the middle of the screen, I view this draw box not inside the sprite box, else in another part of the screen. How can I view the draws exactly where sprites are?

Thanks.

If the debug drawing doesn’t coincide with the sprite positions then you are calculating it differently in two places.

You must calculate a sprite’s position from the box2d position, and that involves some sort of scaling (box2d works in meters, your screen works in pixels - so something like 32 pixels per meter must be set, somewhere)

If you use a different number (or offset, if one is used) in the sprite positioning vs the debug draw, then that will cause the debug to be drawn elsewhere compared to the sprite.

@Maxxx Thanks for the answer!
I understand you, but I’m scaling the positions in box2d.
This is my code for create a Box in coco2d and box2d:

#define SCALE_RATIO 50.0f

auto visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();

Sprite *box = Sprite::create("box.png");
box->setPosition( (origin.x + visibleSize.width/2), (origin.y + visibleSize.height/2) );
scene->addChild(box);

b2BodyDef bd;
bd.type = b2_staticBody;
bd.position = b2Vec2( (origin.x + visibleSize.width/2) / SCALE_RATIO, (origin.y + visibleSize.height/2) / SCALE_RATIO);
bd.userData = box;
       
b2Body *b;
b2PolygonShape bps;
        
b = world->CreateBody(&bd);

bps.SetAsBox( box->getBoundingBox().size.width/2) / SCALE_RATIO, (box->getBoundingBox().size.height/2) / SCALE_RATIO);
        
b->CreateFixture(&bps, 0);

What is my problem?
In the update() method, when I update the sprite positions, I multiplied the SCALE_RATIO instead of dividing it.

Thanks.

I don’t have time to look in detail right now, but try this:
Set your box2d object in a fixed position using no multiplier - e.g. set it to (10,10)
Work out what your sprite position should be from this
e.g. 10 * multiplier, 10 * multiplier

Don’t update anything, just display that.
Look where your sprite is and look where your box2d debug is
Remember, the box2d debug is using a calculation to convert its location in meters to pixels, and you need to do the same calculation for your sprite.
Also, don’t worry about the size of the sprite for now!

Once you have worked out what multiplier you are going to use (32 or 64 are the normal values) everything should fall into place!

But the overall rule is to let the box2d position determine the sprite’s position on screen, and not the other way around!

@Maxxx thanks for the answer!
I forgot change this line: _debugDraw = new GLESDebugDraw(32); to 50 (my SCALE_RATIO is 50).
However, I continue having problems.

In many sprites I changed the default AnchorPoint (the default is Vec2(0.5, 0.5) and I changed it to Vec2(0, 1). I detected that if the sprite uses the default anchor point, it works fine. But if not, the sprite and the box2d draw is in different places. It sounds like the box2d draw class always assumes that that the anchor point is 0.5, 0.5.

Is it a bug? I think that the box2d draw should be drawn in base to sprite anchor point setted. But I have no idea what we should edit for fix this bug. GLES-Render.cpp? DebugLayer.cpp?

Thanks.

First: No it is not a bug.
Box2d is a physics simulator - if you choose to use it to provide a graphical representation using sprites then it is up to you to position the sprites where the physics engine says they are.
The physics engine says a box with side of 1m is at (30,20) in the physics world, then it is up to you to place your sprite in a suitable screen position for display.
Box2d provides a debug draw to help you debug. It is obviously convenient for you to draw your sprites in the same place that box2d draws its debug representation of the world.
If you choose not to (which you are by setting your anchor point to (0,1) then that won’t work!
The question is, why are you choosing to set your anchor point differently?
When using a physics engine you really should be coding “physics first” - so set up your model in Box2d then position your sprites accordingly - so leaving the anchor point at (0.5,0.5) makes this approximately 30,000,000 times easier!!!
If you have a non-central offset then you will need to calculate the position of the sprite based upon its dimensions, converted to meters - which is one heck of an overhead!!!

I’m choosing to set the anchor point differently for convenience. If coco2d provides this method I think that is for use it :smile:. I could adapt my sprites to the default anchor point. Reading your answer I think that I have not another alternative :wink:

Thanks for your advices!

This is what I generally use:

Rect aabb = someNode->getBoundingBox();
DrawNode* drawNode = DrawNode::create();
drawNode->drawRect(aabb.origin, aabb.origin + aabb.size, Color4F(1, 0, 0, 1));
this->addChild(drawNode, 100);

Where this is some parent node. I’ve even added this to the node itself (e.g. someNode) and that also seems to work, just make sure your z-index is high enough and change your origin etc.

No worries.
Lots of people start with physics engines the same as you have - by positioning the images first then trying to use physics.
Doing it physics-only means the anchor point is no more or less convenient as everything will be positioned according to the physics

@Maxxx
I’m trying debug box2d with your code with cocos2d-x 3.16 and xCode 9.2.
It doesn’t work. Why? A few months ago it worked haha. Maybe it has problems with the new cocos version?

I am using XCode 9.2 and cocos2d-x 3.16 without issue with pretty much the code above, so I’m not sure what you’ve got that’s difference.