备注:由于本人最近在学习box2d引擎,而中文资料中好的文章比较少,我就在google上找了一些英文资料。于是,发现了网上的Box2D tutorial系列文章,觉得写得挺好的,于是做了一些翻译和大家分享分享。由于这是我第一次翻译技术型文章,翻译不当的地方还请各位多理解。

下面我给出原文网址:http://www.iforce2d.net/b2dtut/debug-draw,本系列翻译文章仅用于学习交流之用,请勿用于商业用途。欢迎各位转载!

使用debug draw

Testbed充分使用了debugdraw的特征来画各种各样的形状。如果你想开发一个游戏,你当然想要各种炫目的图形而不是一些无聊的多边形,当你无法获取物理场景正常工作时,debug draw这一特点会非常的有用。有时候问题会出现在渲染一部分你的游戏中,例如一个sprite显示在一个错误的位置或旋转角度,这让就无法表现出正确的物理现象。我建议当你想检查在Box2d世界中发生什么的时候,最好每次都保持debug draw。

它的工作原理非常简单。Box2D会告诉你所有的形状和它们的位置等等信息。如“一个半径为r的圆在x,y位置”或者“从a到b的边”等等,还有你可以画被告知要画的内容。你不用做任何的转换工作或者担心五日的实际位置以及那个fixtures属于那个bodies,你仅仅只要做的是画出几何图形。如果你只是想花几条线段而已,那么你就不能把这搞砸了。

Testbed使用的默认debugdraw是继承了b2DebugDraw类,b2DebugDraw有大量的虚函数可以覆盖。这里是一些主要的成员:

virtualvoid DrawPolygon(b2Vec2* vertices, int32 vertexCount, b2Color& color)=0;

virtualvoid DrawSolidPolygon(b2Vec2* vertices, int32 vertexCount, b2Color& color)=0;

virtualvoid DrawCircle(b2Vec2& center, float32 radius, b2Color& color)=0;

virtualvoid DrawSolidCircle(b2Vec2&center,float32 radius,b2Vec2& axis, b2Color& color)=0;

virtualvoid DrawSegment(b2Vec2& p1, b2Vec2& p2, b2Color& color)=0;

virtualvoid DrawTransform(const b2Transform& xf)=0;

尽管testbed的默认debug draw工作的很好而且我们也不用去修改它,因为我们的话题只是让我们试着用自己的来来改变一点外观。之前场景中的话题都可以适用,我用使用跟“匀速运动”这一话题的相同场景。

要想创建我们自己的debug draw类,我们需要实现所有的纯虚函数。现在我们使这些函数全部为空函数:

class FooDraw : publicb2DebugDraw
  {
  public:
    void DrawPolygon(constb2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
    void DrawSolidPolygon(constb2Vec2* vertices, int32 vertexCount, const b2Color& color) {}
    void DrawCircle(constb2Vec2& center, float32 radius, const b2Color& color) {}
    void DrawSolidCircle(constb2Vec2& center, float32 radius, constb2Vec2& axis, const b2Color& color) {}
    void DrawSegment(constb2Vec2& p1, constb2Vec2& p2, const b2Color& color) {}
    void DrawTransform(const b2Transform& xf) {}
  };

要告诉Box2D使用我们创建的类而不是默认,我们可以使用SetDebugDraw函数。这个函数需要一个指向b2DebugDraw对象的指针,因此我们需要一个类的实例来指向。这个可以通过在全局作用于处声明一个你自己创建的类对象。

//at global scope
  FooDraw fooDrawInstance;
  
  //in constructor, usually
  m_world->SetDebugDraw( &fooDrawInstance );
  
  //somewhere appropriate
  fooDrawInstance.SetFlags( b2DebugDraw::e_shapeBit );

这会告诉世界类的实例是什么,以及传递所有的绘图指令。注意最后部分,选择一个类的调试信息显示。我们现在最感兴趣的是观察世界中的shapes(fixtures),但你也可以使用这个标志包括以下内容:

·        e_shapeBit ( draw shapes)

·        e_jointBit ( draw jointconnections

·        e_aabbBit ( draw axisaligned bounding boxes )

·        e_pairBit ( drawbroad-phase pairs )

·        e_centerOfMassBit ( drawa marker at body CoM )

我说把这个setting放在一个合适的位置,因为你可能在运行时会想修改一些东西,就想上边说到的情形,你可能有事后想确认你的渲染游戏实体和Box2D正在做同样的事。在testbed中,你可以看到这些settings,选项框就在右边的控制面板上。

现在运行testbed,你在场景中应该什么也见不到。这是因为我们没有实现debug draw。从这一点来看,你在drawing函数中添加的内容取决于是用的平台和渲染用的api。举个例子,让我们在OpenGL ES中实现DrawSolidPolygon函数,作为嵌入式平台,如iphone。这是一个简单的例子,因为OpenGL ES是OpenGL的子集,因此我们可以在PC机上的testbed中正常运行,同样因为这是其中一个经常出现的问题。

OpenGLES没有glBegin/glEnd/glVertex函数,因此我们使用vertex数组来实现渲染。

void DrawSolidPolygon(constb2Vec2* vertices, int32 vertexCount,const b2Color&color)

{

//set up vertexarray

GLfloat glverts[16]; //allow for polygons up to 8 vertices

glVertexPointer(2, GL_FLOAT, 0, glverts);//tell OpenGLwhere to find vertices

glEnableClientState(GL_VERTEX_ARRAY);//use vertices in subsequent calls toglDrawArrays

 

//fill in vertexpositions as directed by Box2D

for (int i = 0; i <vertexCount; i++) {

glverts[i*2]   =vertices[i].x;

glverts[i*2+1] = vertices[i].y;

}

 

//draw solidarea

glColor4f( color.r, color.g, color.b, 1);

glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);

 

//draw lines

glLineWidth(3); //fat lines

glColor4f( 1, 0, 1, 1 ); //purple

glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

}

其他的drawing函数都可以像这样来修改。圆形可能需要被画成一个拥有许多边的多边形,这取决于你使用的渲染api.

更新:我中注意到了一个很好地实现了OpenGLES debug draw的Box2d源代码iphone。这是写给Obj-C的,但它看起来很像C++,因此你可以直接使用它而无需修改:GLES-Render.mm

打赏

发表评论

您的电子邮箱地址不会被公开。