I can't get Box2d debug draw to work

Hey guys,

i am working with Cocos2d-x 3.7.1 on windows. I try to display the Box2d debug draw. But even the examples that i found here in the forums did not work. Maybe because they are not made with the latest version. Some of them are pretty old. Now a am using the B2DebugDraw class from https://github.com/vinova/B2DebugDraw

Still no success.

I just don’t know what i am missing or what i am doing wrong. Does anybody of you guys use the debug draw functionality in 3.7.1?

Thanks in advance
Kande

1 Like

Here’s my DebugLayer.cpp - there’s some additional stuff (I have some debug labels and things that I can show, such as a grid so I can see locations of various objects - but the basics are all here.

In my main code I simply have

   #ifdef DEBUG
    	scene->addChild(Globals::debugLayer, GlobalEnums::ZOrder::foregroundFG);
    	auto debugLayer = DebugLayer::create();
    #endif

…

#include "DebugLayer.h"
#include "Utils.h"
#include "Globals.h"

USING_NS_CC;


bool DebugLayer::init()
{
	if (!Layer::init())
	{
		return false;
	}
	// set up box2d ratio and debug flags
	float32 ratio = (float32) Utils::screenFromMeters(1.0);
	_debugDraw = new GLESDebugDraw(ratio);
	Globals::box2dWorld->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);

	this->setupDebugScreen();

//	this->debugLevel = DebugLayer::debugLevelBitMap::none;
	Globals::showMessage = true;


	return true;
}

void DebugLayer::draw(Renderer* renderer, const Mat4& transform, uint32_t flags)
{
	cocos2d::Layer::draw(renderer, transform, flags);

	if (Globals::showBox2dDebug)
	{
		GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION);
        Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
		// Translate the debug draw so it matches our visible world...
		auto p = Utils::screenPointFromPoint(Globals::getVisibleWorldLeftBottomInMeters());
		// Note I add 1 to the y to make the debug draw visible over the top of the subterrain as I can't get the debug draw layer to show on top!
		kmGLTranslatef(-p.x, -p.y , 0);

		Globals::box2dWorld->DrawDebugData();

        Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

	}
	if (Globals::showGrid)
	{
		this->drawScreenGrid();
	}

	_gridLabel->setVisible((Globals::showGrid));
	_debugLabel->setVisible((Globals::showMessage));

}

void DebugLayer::setupDebugScreen()
{
	_debugLabel = Label::createWithSystemFont("PooperPig v0.1", "myFontName", 24);
	_debugLabel->setPosition(Point(10, 64));
	_debugLabel->setAnchorPoint(Point(0.0f, 0.0f));
	this->addChild(_debugLabel);

//    _gridLabel = Label::create("Grid label", "myFontName", 24);
    _gridLabel = Label::createWithSystemFont("Grid label", "myFontName", 24);
	_gridLabel->setAnchorPoint(Point(0.0f, 0.0f));
	this->addChild(_gridLabel);

}

void DebugLayer::setDebugString(std::string text)
{
	_debugLabel->setString(text);
}

/*
	Draw grid and debug info on screen
 */
void DebugLayer::drawScreenGrid()
{
	int mx = 10; // how many meters between grid lines
	int my = 10; // how many meters between grid lines
	Vec2 p = Globals::getVisibleWorldLeftBottomInMeters();

	int x = (int) p.x % mx;
	x = (int) (x >= (mx / 2) ? (p.x - x + mx) : (p.x - x));

	p.x = (float) x;

	int y = (int) p.y % my;
	y = (int) (y >= (my / 2) ? (p.y - y + my) : (p.y - y));

	p.y = (float) y;


	for (int i = 0; i < 20; i++)
	{
		auto p0 = Utils::screenPointFromWorldPoint(Vec2(p.x + i * mx, 0));
		auto p1 = Utils::screenPointFromWorldPoint(Vec2(p.x + i * mx, 700));
		cocos2d::DrawPrimitives::drawLine(p0, p1);
	}

	for (int i = 0; i < 20; i++)
	{
		auto p0 = Utils::screenPointFromWorldPoint(Vec2(0, p.y + i * my));
		auto p1 = Utils::screenPointFromWorldPoint(Vec2(1000, p.y + i * my));
		cocos2d::DrawPrimitives::drawLine(p0, p1);
	}

	p = Vec2(p.x + mx, p.y + my + 2);

	auto s = Utils::formatString("%d,%d", (int) p.x, (int) p.y);
	_gridLabel->setString(s);
	
	
	_gridLabel->setPosition(Utils::screenPointFromWorldPoint(p));

}

DebugLayer::DebugLayer()
{

}

DebugLayer::~DebugLayer()
{

}

and here’s DebugLayer.h

#ifndef __DebugLayer_H_
#define __DebugLayer_H_

#include "CCLayer.h"
#import "GLES-Render.h"

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

	void setupDebugScreen();

	cocos2d::Label* _debugLabel;
	cocos2d::Label* _gridLabel;

	void drawScreenGrid();


public:
	CREATE_FUNC(DebugLayer);

	virtual bool init();

	DebugLayer();

	~DebugLayer();

    virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4& transform, uint32_t flags);

	void setDebugString(std::string text);


};


#endif //__DebugLayer_H_

Hey Maxxx,

thanks for the answer. Much more detailed than i expected. Unfortunately i start to think, that there is something wrong with my installation. I do not have the Globals.h and the Utils.h anywhere. Are these files Box2d header files or did you implement these files yourself?

Cheers
Kande

Globals and Utils are my own stuff - you can pretty much ignore them & guess at what they are used for in the code…

Try this
//

#ifndef __DebugLayer_H_
#define __DebugLayer_H_

#include "CCLayer.h"
#import "GLES-Render.h"

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


public:
	CREATE_FUNC(DebugLayer);

	virtual bool init();

	DebugLayer();

	~DebugLayer();

    virtual void draw(cocos2d::Renderer *renderer, const cocos2d::Mat4& transform, uint32_t flags);




};


#endif //__DebugLayer_H_

//

#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);
	Globals::box2dWorld->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);

	Globals::box2dWorld->DrawDebugData();

    Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);


}


DebugLayer::DebugLayer()
{

}

DebugLayer::~DebugLayer()
{

}
1 Like

Thanks man, the thing is, that i have seen the Globals.h several times in examples on the net. So i thought i am missing it in my installation or whatever. I will get the Utils and Globals stuff out or even better create my own ones… they look pretty handy to me :smile:

Thanks and cheers
Kande

I use Utils for all sorts of, well, Utility functions - handy to have just one place to look!

Globals has a bunch of stuff in there so it can be accessed from anywhere - so it has public properties for the various layers, and also my Player object -

So if I do need to check my player’s location from within any other class I can do so via Globals::

Not necessarily the most elegant way of doing it - but very efficient!

It works! Thanks man, you really helped me a lot! I just created a class that provides me with data like a pointer to the b2World etc. I know, singletons or globals are not always the preffered solution. But for lazy people like me they are awesome :smile:

Thanks again
Kande

Hello,

I just used DebugLayer and all works fine. However, when I tried to add it on top of all Node’s on my scene - I get that Box2D drawing actually shown bellow of all Node’s.

Most fun thing is this code:

B2DebugDrawLayer *layer = B2DebugDrawLayer::create(world, PTM_RATIO);
Sprite *spr = Sprite::createWithSpriteFrameName("UI/achiev_25.png");
thisScene->addChild(spr,99999);
spr->addChild(layer);

spr - drawn at the top of everything, but at the same time - debug draw is bellow everything /

How this can be and fixed? @Maxxx @zhangbin @zhangxm @slackmoehrle ?

So we have to call this function in our TestScene ?

How do we actually make it appear ?