Box2D Debug Draw not working

I have Box2D working it appears

I am generally building on Visual Studio and Android studio at my side to check it working on android phone every now and then

Classes
TestScene
GaddBox - My API layer class I am working on for project
B2DebugDrawLayer : public cocos2d::Layer
GLESDebugDraw : public b2Draw

I’ll list files below

My question is how in earth do I use them. How can i make the debug actually draw something

I have two circles bodies in scene bouncing off each other so b0x2d is working. However, the ball seems to fall really slowly, its set to -9.y. Doesnt look like earth gravity, looks too slow.

And there is how ot make debug draw correctly . I read 15 web sites pages, Sonar Syytems, Ray, looked at the test.cpp files. I cant figure it out. The test.cpp files are hard for me to understand and i dont evern think the two box2d test folders have and debug drawing inside

Someone please let me know a handful of examples of how i make the debug draw work

My guess is I stick this function in my update function ??? But i do not know how to get parameters for it with my boidy objects and sprite objects

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

Thanks

GaddBox Header File

b2World* m_B2World;

GaddBox CPP Init()

b2Vec2 gravity;
gravity.Set(0.0f, -9.8f);
m_B2World = new b2World(gravity);
m_B2World->SetAllowSleeping(true);
m_B2World->SetContinuousPhysics(true);

m_B2DebugDrawLayer = B2DebugDrawLayer::create(m_B2World, PTM_RATIO);
m_B2DebugDrawLayer->setAnchorPoint(Point::ZERO);
m_B2DebugDrawLayer->setPosition(Point::ZERO);
m_MainLayer->addChild(m_B2DebugDrawLayer, 12);

m_Sprite = cocos2d::Sprite::create("mis/blueDot50.png");
m_MainLayer->addChild(m_Sprite, 1);
m_Body = createPhysicsBody("Test_Body", m_Sprite, cocos2d::Vec2(0, 0), 1, 1, 1, true, false, true, 1);

m_SpriteII = cocos2d::Sprite::create("mis/blueDot50.png");
m_MainLayer->addChild(m_SpriteII, 1);
m_BodyII = createPhysicsBody("Test_BodyII", m_SpriteII, cocos2d::Vec2(0, -50), 1, 1, 1, true, true, true, 1);

GaddBox Update()

	float32 timeStep = 1 / 60.0;
	int32 velocityIterations = 8;
	int32 positionIterations = 3;
	m_B2World->Step(delta, velocityIterations, positionIterations);

	m_Sprite->setPosition(cocos2d::Vec2(m_Body->GetPosition().x, m_Body->GetPosition().y));

	m_B2World->ClearForces();

B2DebugDrawLayer H

#ifndef B2DEBUGDRAWLAYER_H
#define B2DEBUGDRAWLAYER_H

#include "cocos2d.h"
#include "Box2D/Box2D.h"
#include "GLES-Render.h"

using namespace cocos2d;

class B2DebugDrawLayer : public Layer
{
	  b2World* mB2World;
	  GLESDebugDraw* mB2DebugDraw;
	  const float mPtmRatio;
 
	public:
	  B2DebugDrawLayer(b2World* pB2World, float pPtmRatio);
	  static B2DebugDrawLayer* create(b2World* pB2World, float pPtmRatio);
	  virtual bool init();
	  virtual void draw(Renderer *renderer, const Mat4& transform, uint32_t flags);
    
	protected:
		Mat4 _modelViewMV;
		void onDraw();
		CustomCommand _customCommand;

};

#endif // DEFINE B2DEBUGDRAWLAYER_H

B2DebugDrawLayer CPP

#include "B2DebugDrawLayer.h"

using namespace cocos2d;

B2DebugDrawLayer* B2DebugDrawLayer::create(b2World* pB2World, float pPtmRatio)
{
	B2DebugDrawLayer *pRet = new B2DebugDrawLayer(pB2World, pPtmRatio);

	if (pRet && pRet->init()){

		pRet->autorelease();
		return pRet;
	}
	else{

		delete pRet;
		pRet = NULL;
		return NULL;
	}

}

B2DebugDrawLayer::B2DebugDrawLayer(b2World* pB2World, float pPtmRatio): 
	mB2World(pB2World), 
	mPtmRatio(pPtmRatio)
{}

bool B2DebugDrawLayer::init(){

	if(!Layer::init()){return false;}
  
	CCLOG("INITIALIZING B2DebugDrawLayer");
    
	mB2DebugDraw = new GLESDebugDraw( mPtmRatio );
	mB2World->SetDebugDraw(mB2DebugDraw);
  
	uint32 flags = 0;

	//    flags += b2Draw::e_shapeBit;
	//    flags += b2Draw::e_jointBit;
	//    flags += b2Draw::e_aabbBit;
	//    flags += b2Draw::e_pairBit;
	//    flags += b2Draw::e_centerOfMassBit;

	mB2DebugDraw->SetFlags(flags);
  
	return true;

}

void B2DebugDrawLayer::draw(Renderer *renderer, const Mat4& transform, uint32_t flags)
{
    // IMPORTANT: It is recommend to use option:1 and comment option:2, becuase option:2 is only for debuging purpose, else performance would be down.
    
	//    //OPTION:1
	//    Layer::draw(renderer, transform, flags);
	//    Director* director = Director::getInstance();
	//    GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION );
	//    director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
	//    mB2World->DrawDebugData();
	//    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    //OPTION:2
    GL::enableVertexAttribs( cocos2d::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);

    _modelViewMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

    _customCommand.init(_globalZOrder);
    _customCommand.func = CC_CALLBACK_0(B2DebugDrawLayer::onDraw, this);
    renderer->addCommand(&_customCommand);

    director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    
}

void B2DebugDrawLayer::onDraw(){

    Director* director = Director::getInstance();
    CCASSERT(nullptr != director, "Director is null when seting matrix stack");

    Mat4 oldMV;
    oldMV = director->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
    director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, _modelViewMV);
    mB2World->DrawDebugData();
    director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, oldMV);

}

GLES-Render H

#ifndef RENDER_H
#define RENDER_H
#include "Box2D/Box2D.h"
#include "cocos2d.h"

struct b2AABB;

// This class implements debug drawing callbacks that are invoked inside b2World::Step->()

class GLESDebugDraw : public b2Draw
{

		float32 mRatio;
		cocos2d::GLProgram* mShaderProgram;
		GLint mColorLocation;

		void initShader( void );
	public:
		GLESDebugDraw();

		GLESDebugDraw( float32 ratio );

		virtual void DrawPolygon(const b2Vec2* vertices, int vertexCount, const b2Color& color);

		virtual void DrawSolidPolygon(const b2Vec2* vertices, int vertexCount, const b2Color& color);

		virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);

		virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);

		virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);

		virtual void DrawTransform(const b2Transform& xf);

		virtual void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color);

		virtual void DrawString(int x, int y, const char* string, ...); 

		virtual void DrawAABB(b2AABB* aabb, const b2Color& color);

};


#endif

GLES-Render CPP

#include "GLES-Render.h"
#include "cocos2d.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

USING_NS_CC;

GLESDebugDraw::GLESDebugDraw()
    : mRatio( 1.0f )
{
    this->initShader();
}

GLESDebugDraw::GLESDebugDraw( float32 ratio )
    : mRatio( ratio )
{
    this->initShader();
}

void GLESDebugDraw::initShader( void )
{
    mShaderProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_U_COLOR);

    mColorLocation = glGetUniformLocation( mShaderProgram->getProgram(), "u_color");
}

void GLESDebugDraw::DrawPolygon(const b2Vec2* old_vertices, int vertexCount, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    b2Vec2* vertices = new b2Vec2[vertexCount];
    for( int i=0;i<vertexCount;i++) 
    {
        vertices[i] = old_vertices[i];
        vertices[i] *= mRatio;
    }

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,vertexCount);


    CHECK_GL_ERROR_DEBUG();

    delete[] vertices;
}

void GLESDebugDraw::DrawSolidPolygon(const b2Vec2* old_vertices, int vertexCount, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    b2Vec2* vertices = new b2Vec2[vertexCount];
    for( int i=0;i<vertexCount;i++) {
        vertices[i] = old_vertices[i];
        vertices[i] *= mRatio;
    }
    
    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r*0.5f, color.g*0.5f, color.b*0.5f, 0.5f);

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, vertices);

    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(2,vertexCount*2);

    CHECK_GL_ERROR_DEBUG();

    delete[] vertices;
}

void GLESDebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    const float32 k_segments = 16.0f;
    int vertexCount=16;
    const float32 k_increment = 2.0f * b2_pi / k_segments;
    float32 theta = 0.0f;
    
    GLfloat*    glVertices = new GLfloat[vertexCount*2];
    for (int i = 0; i < k_segments; ++i)
    {
        b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
        glVertices[i*2]=v.x * mRatio;
        glVertices[i*2+1]=v.y * mRatio;
        theta += k_increment;
    }
    
    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, glVertices);

    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,vertexCount);

    CHECK_GL_ERROR_DEBUG();

    delete[] glVertices;
}

void GLESDebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    const float32 k_segments = 16.0f;
    int vertexCount=16;
    const float32 k_increment = 2.0f * b2_pi / k_segments;
    float32 theta = 0.0f;
    
    GLfloat*    glVertices = new GLfloat[vertexCount*2];
    for (int i = 0; i < k_segments; ++i)
    {
        b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
        glVertices[i*2]=v.x * mRatio;
        glVertices[i*2+1]=v.y * mRatio;
        theta += k_increment;
    }
    
    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r*0.5f, color.g*0.5f, color.b*0.5f, 0.5f);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, glVertices);
    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);


    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    // Draw the axis line
    DrawSegment(center,center+radius*axis,color);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(2,vertexCount*2);

    CHECK_GL_ERROR_DEBUG();

    delete[] glVertices;
}

void GLESDebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);

    GLfloat    glVertices[] = 
    {
        p1.x * mRatio, p1.y * mRatio,
        p2.x * mRatio, p2.y * mRatio
    };
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, glVertices);

    glDrawArrays(GL_LINES, 0, 2);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,2);

    CHECK_GL_ERROR_DEBUG();
}

void GLESDebugDraw::DrawTransform(const b2Transform& xf)
{
    b2Vec2 p1 = xf.p, p2;
    const float32 k_axisScale = 0.4f;
    p2 = p1 + k_axisScale * xf.q.GetXAxis();
    DrawSegment(p1, p2, b2Color(1,0,0));

    p2 = p1 + k_axisScale * xf.q.GetYAxis();
    DrawSegment(p1,p2,b2Color(0,1,0));
}

void GLESDebugDraw::DrawPoint(const b2Vec2& p, float32 size, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);

    //    glPointSize(size);

    GLfloat                glVertices[] = {
        p.x * mRatio, p.y * mRatio
    };

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, glVertices);

    glDrawArrays(GL_POINTS, 0, 1);
    //    glPointSize(1.0f);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,1);

    CHECK_GL_ERROR_DEBUG();
}

void GLESDebugDraw::DrawString(int x, int y, const char *string, ...)
{
//    NSLog(@"DrawString: unsupported: %s", string);
    //printf(string);
    /* Unsupported as yet. Could replace with bitmap font renderer at a later date */
}

void GLESDebugDraw::DrawAABB(b2AABB* aabb, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);

    GLfloat                glVertices[] = {
        aabb->lowerBound.x * mRatio, aabb->lowerBound.y * mRatio,
        aabb->upperBound.x * mRatio, aabb->lowerBound.y * mRatio,
        aabb->upperBound.x * mRatio, aabb->upperBound.y * mRatio,
        aabb->lowerBound.x * mRatio, aabb->upperBound.y * mRatio
    };

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, 0, glVertices);
    glDrawArrays(GL_LINE_LOOP, 0, 4);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,4);

    CHECK_GL_ERROR_DEBUG();
}

Hi. It’s my debugdraw class and it works in cocos2d-x 3.15.

just create your scene and add this line of code to it:
B2DebugDrawLayer.cpp (2.9 KB)
B2DebugDrawLayer.h (1.8 KB)
GLES-Render.cpp (7.7 KB)
GLES-Render.h (2.1 KB)

#include "GLES-Render.h"
#include "B2DebugDrawLayer.h"


// create world
// Define the gravity vector.
b2Vec2 gravity;
gravity.SetZero();

// Do we want to let bodies sleep?
bool doSleep = false;

// Construct a world object, which will hold and simulate the rigid bodies.
_world = new b2World(gravity);
_world->SetAllowSleeping(doSleep);

// create debugDrawNode
auto b = B2DebugDrawLayer::create(_world);
addChild(b);
1 Like

I did add your layer it appears. In my init fucntion i have this code

b2Vec2 gravity;
gravity.Set(0.0f, -9.8f);
m_B2World = new b2World(gravity);
m_B2World->SetAllowSleeping(true);
m_B2World->SetContinuousPhysics(true);

m_B2DebugDrawLayer = B2DebugDrawLayer::create(m_B2World, PTM_RATIO);
m_B2DebugDrawLayer->setAnchorPoint(Point::ZERO);
m_B2DebugDrawLayer->setPosition(Point::ZERO);
m_MainLayer->addChild(m_B2DebugDrawLayer, 12);

m_Sprite = cocos2d::Sprite::create("mis/blueDot50.png");
m_MainLayer->addChild(m_Sprite, 1);
m_Body = createPhysicsBody("Test_Body", m_Sprite, cocos2d::Vec2(0, 0), 1, 1, 1, true, false, true, 1);

I do not fully understand what that PTM_Ratio values ? A scaling value. I did find webpage that explained it, ill have to go back and read it. Here is the create B2Body function.

b2Body* GaddBox::createPhysicsBody(const std::string &imageName, cocos2d::Sprite *sprite, cocos2d::Point position, float density, float friction, float restitution, bool isCircle, bool isStatic, bool isVisible, int groupIndex)
{
	
	b2FixtureDef bodyFixture;
	b2CircleShape circle;
	b2BodyDef bodyDef;
	b2Body* body;

	circle.m_radius = sprite->getBoundingBox().size.width / 2;

	bodyFixture.density = density;
	bodyFixture.friction = friction;
	bodyFixture.restitution = restitution;
	bodyFixture.filter.groupIndex = groupIndex;
	bodyFixture.shape = &circle;

	bodyDef.type = isStatic ? b2_staticBody : b2_dynamicBody;
	bodyDef.position.Set(position.x, position.y);
	bodyDef.userData = sprite;

	body = m_B2World->CreateBody(&bodyDef);
	body->CreateFixture(&bodyFixture);

	return body;

}

Inside my update function there is this code

	float32 timeStep = 1 / 60.0;
	int32 velocityIterations = 8;
	int32 positionIterations = 3;
	m_B2World->Step(delta, velocityIterations, positionIterations);

	m_Sprite->setPosition(cocos2d::Vec2(m_Body->GetPosition().x, m_Body->GetPosition().y));

	m_B2World->ClearForces();

So it appears I already have all the code from your reply added and all i see is the blue sprite ball only

You have a comment

// This class implements debug drawing callbacks that are invoked inside b2World::Step->()

Does this mean I do not need call it in update . Like it works itself away with out any required updating in the scene update function ?

Hold on. It is required add the GLES header even, in the scene class ?

I did just try with no effect ?

Need your wisdom Amin13A , no idea how these work !!! :frowning:

PTM means pixel per meter. Cocos positioning based on pixels but box2d positioning based on meters. This ratio convert this. Your debug draw is already drawn in your scene but it is outside of screen.
#define PTM_RATIO 1.f
Now your positioning works.

Didn’t do anything. Any ideas

i am using the files here:


this works for me:

B2DebugDrawLayer *debugDrawLayer = B2DebugDrawLayer::create(PhysicsBase::getInstance()->_world, PTM_RATIO);
_gameNode->addChild(debugDrawLayer);

Physicsbase is a singleton that I use to access b2world at anytime and other stuff…

Keep in mind that this thing has to be added last to the node or with a high z index to work.

Still no luck, no debug data showing up, also i debugged through the files to see if its stepping through there code and it seems to be doing so fine, just nothing displayed

Please help anyone ?

:frowning:

Please remove any BG, if you have any.
Because Box2d debug draw may be drawing behind your sprites, thats how its working for me.

Whats BG ?

i di get it working now. I just need sort this conversion thing out now is all for meters and pixels

Thanks all

When I include these files in my android studio build, it break and exits with error code 1.

Tool me ages filter it down to including these two lines in the init function where we construct (Anims files) the debug layer.

However, it works fine now on the win32 build. When i exclude it, android works, when i include it android break

Can anyone advise how to solve issue

I changed the render class file name to remove “-” and it now works on android. !!