この記事は
SDL+OpenGLのゲームにBox2D組み込むのにいろいろいじって勉強しようと思ったけど、ソースコード一個にまとまったごくごく簡単な描画付きサンプルないよなー? って思って自分で作りましたの記事です。
環境とか
- windows 7 professional 32bit
- Visual Studio 2010
- Box2D 2.2.1
- SDL 1.2.15
プログラムの概要
ソースコード
#include <iostream> #include <sstream> #include <stdexcept> #include <SDL.h> #include <SDL_opengl.h> #include <Box2D/Box2D.h> // デバッグ描画クラス. //中身はTestBedのFramework内のRender.cppから一部コピペ. class CDebugDrawer : public b2Draw{ public: //コンストラクタ.何もしない. CDebugDrawer(){ } //デストラクタ.継承なので. virtual ~CDebugDrawer(){ } /// Draw a closed polygon provided in CCW order. virtual void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color){ glColor3f(color.r, color.g, color.b); glBegin(GL_LINE_LOOP); for (int32 i = 0; i < vertexCount; ++i) { glVertex2f(vertices[i].x, vertices[i].y); } glEnd(); } /// Draw a solid closed polygon provided in CCW order. virtual void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color){ glEnable(GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); glBegin(GL_TRIANGLE_FAN); for (int32 i = 0; i < vertexCount; ++i) { glVertex2f(vertices[i].x, vertices[i].y); } glEnd(); glDisable(GL_BLEND); glColor4f(color.r, color.g, color.b, 1.0f); glBegin(GL_LINE_LOOP); for (int32 i = 0; i < vertexCount; ++i) { glVertex2f(vertices[i].x, vertices[i].y); } glEnd(); } /// Draw a circle. virtual void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color){ const float32 k_segments = 16.0f; const float32 k_increment = 2.0f * b2_pi / k_segments; float32 theta = 0.0f; glColor3f(color.r, color.g, color.b); glBegin(GL_LINE_LOOP); for (int32 i = 0; i < k_segments; ++i) { b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); glVertex2f(v.x, v.y); theta += k_increment; } glEnd(); } /// Draw a solid circle. virtual void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color){ const float32 k_segments = 16.0f; const float32 k_increment = 2.0f * b2_pi / k_segments; float32 theta = 0.0f; glEnable(GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f); glBegin(GL_TRIANGLE_FAN); for (int32 i = 0; i < k_segments; ++i) { b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); glVertex2f(v.x, v.y); theta += k_increment; } glEnd(); glDisable(GL_BLEND); theta = 0.0f; glColor4f(color.r, color.g, color.b, 1.0f); glBegin(GL_LINE_LOOP); for (int32 i = 0; i < k_segments; ++i) { b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta)); glVertex2f(v.x, v.y); theta += k_increment; } glEnd(); b2Vec2 p = center + radius * axis; glBegin(GL_LINES); glVertex2f(center.x, center.y); glVertex2f(p.x, p.y); glEnd(); } /// Draw a line segment. virtual void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color){ glColor3f(color.r, color.g, color.b); glBegin(GL_LINES); glVertex2f(p1.x, p1.y); glVertex2f(p2.x, p2.y); glEnd(); } /// Draw a transform. Choose your own length scale. /// @param xf a transform. virtual void DrawTransform(const b2Transform& xf){ b2Vec2 p1 = xf.p, p2; const float32 k_axisScale = 0.4f; glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(p1.x, p1.y); p2 = p1 + k_axisScale * xf.q.GetXAxis(); glVertex2f(p2.x, p2.y); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(p1.x, p1.y); p2 = p1 + k_axisScale * xf.q.GetYAxis(); glVertex2f(p2.x, p2.y); glEnd(); } }; using namespace std; namespace{ const int _ScreenWidth = 640; //スクリーン解像度 const int _ScreenHeight = 480; const float _DrawScaler = 0.5f; //描画時の座標倍率 } //SDLとOpenGLの初期化を行う void InitSDLGL(){ //SDLの初期化 if( SDL_Init(SDL_INIT_VIDEO) ){ ostringstream oss; oss << "SDLの初期化に失敗" << endl; oss << SDL_GetError() << endl; throw runtime_error(oss.str()); } //バッファリングとVSYNCの設定 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 1); //ウィンドウを生成 SDL_Surface* pScreen = SDL_SetVideoMode(_ScreenWidth, _ScreenHeight, 0, SDL_OPENGL); if(!pScreen){ ostringstream oss; oss << "SDLによるOpenGLの初期化に失敗" << endl; oss << SDL_GetError() << endl; throw runtime_error(oss.str()); } //OpenGLの描画設定 glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glViewport(0.0f, 0.0f, _ScreenWidth, _ScreenHeight); glOrtho(-_ScreenWidth/2.f*_DrawScaler, _ScreenWidth/2.f*_DrawScaler, -_ScreenHeight/2.f*_DrawScaler, _ScreenHeight/2.f*_DrawScaler, 1.f, -1.f); } //SDLとOpenGLの解放を行う void ReleaseSDLGL(){ SDL_Quit(); } //指定座標に箱を追加 void AddBox(b2World& world, int mouse_x, int mouse_y){ float x = (mouse_x-(_ScreenWidth/2))*_DrawScaler; float y = (-mouse_y+(_ScreenHeight/2))*_DrawScaler; //動く箱を生成 b2BodyDef BodyDef; BodyDef.type = b2_dynamicBody; BodyDef.position.Set(x, y); b2Body* pBody = world.CreateBody(&BodyDef); b2PolygonShape DynamicBox; DynamicBox.SetAsBox(5.f, 5.f); b2FixtureDef FixtureDef; FixtureDef.shape = &DynamicBox; FixtureDef.density = 1.f; FixtureDef.friction = 0.3f; pBody->CreateFixture(&FixtureDef); } //このプログラムのメインループ void MainLoop(){ //ワールドを生成 b2Vec2 Gravity(0.0f, -10.0f); b2World World(Gravity); //ワールドのデバッグ描画を設定 CDebugDrawer DebugDrawer; DebugDrawer.SetFlags(0x1F); World.SetDebugDraw(&DebugDrawer); //地形ボディを生成 b2BodyDef GroundBodyDef; GroundBodyDef.position.Set(0.f, -10.f); b2Body* pGroundBody = World.CreateBody(&GroundBodyDef); b2PolygonShape GroundBox; GroundBox.SetAsBox(50.f, 10.f); pGroundBody->CreateFixture(&GroundBox, 0.f); const float32 TimeStep = 1.f/60.f; const int32 VelocityIterations = 6; const int32 PositionIterations = 2; //メッセージループ for(;;){ //SDLメッセージを処理 SDL_Event Event; while(SDL_PollEvent(&Event)){ switch(Event.type){ case SDL_QUIT: return; case SDL_MOUSEBUTTONDOWN: AddBox(World, Event.motion.x, Event.motion.y); break; default: break; } } //Box2Dワールドを次のステップに進ませる World.Step(TimeStep, VelocityIterations, PositionIterations); //結果をデバッグ描画 glClear(GL_COLOR_BUFFER_BIT); World.DrawDebugData(); SDL_GL_SwapBuffers(); } } //エントリ関数 int main(int argc, char *argv[]){ //SDL with OpenGLの初期化 InitSDLGL(); //メインループ MainLoop(); //SDL with OpenGLの解放 ReleaseSDLGL(); return 0; }
感想とか
コレをベースにマニュアル読み進めればイケそうな気がする。