Box2D C++教程13-使用debug draw
本文出自https://shuwoom.com博客,欢迎访问!
备注:由于本人最近在学习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¢er,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