Closed5
Box2D基本1_Worldと基本的なオブジェクト

Box2Dv3.0系の使い方
(DxLibと組み合わせて使っています)
オススメ書籍
ゲーム開発で学ぶC言語入門 プロのクリエイターが教える基本文法と開発技法
超本格! サンプルで覚えるC言語 3Dゲームプログラミング教室
Step1: 必要なヘッダーファイル
main.cpp
#include "box2d/box2d.h"
#include "box2d/collision.h"
#include "box2d/math_functions.h"
Step2: Box2Dの大元であるWorldを用意する
main.cpp
// Worldの設定
auto worldDef = b2DefaultWorldDef();
worldDef.gravity = (b2Vec2) {0.0f, -10.0f};
// World
auto worldId = b2CreateWorld(&worldDef);
const string result = b2World_IsValid(worldId) ? "Success!!" : "Failed...";
LOGD("Main", "Hello, Box2D: %s", result.c_str());
Step3: update関数等で、Worldを更新する(delayは秒単位)
main.cpp
b2World_Step(worldId, delay, 8);// Step

Box2Dは、物理演算のみを行う武闘派ライブラリです。
よって、描画処理等からは自力でなんとかしましょうそうしましょう。
Step1: 基底クラスを用意する(ヘッダーは省略)
DrawerBase.cpp
#include "DrawerBase.h"
DrawerBase::DrawerBase(const b2WorldId &worldId,
float x, float y) :
NodeBase(x, y),
color(GetColor(255, 255, 255)),
b2dRate(UtilDebug::getInstance()->getGridSize() * 2),
worldId(worldId) {
//LOGD("Main", "DrawerBase()");
}
DrawerBase::~DrawerBase() {
//LOGD("Main", "~DrawerBase()");
}
float DrawerBase::p2m(float pixel) const {
return pixel / (float) b2dRate;
}
float DrawerBase::m2p(float meter) const {
return meter * (float) b2dRate;
}

先ほどの基底クラスを継承して、四角を描画するクラスを用意します
四角を描画するクラス(ヘッダーは省略)
DrawerBox.cpp
#include "DrawerBox.h"
DrawerBox *DrawerBox::create(const b2WorldId &worldId,
float x, float y,
int w, int h, int deg,
const bool dynamicFlg) {
// New
auto obj = new DrawerBox(worldId, x, y);
if (obj && obj->init(w, h, deg, dynamicFlg)) return obj;
DX_SAFE_DELETE(obj);
return nullptr;
}
DrawerBox::DrawerBox(const b2WorldId &worldId,
float x, float y) : DrawerBase(worldId, x, y),
widthM(0.0f), heightM(0.0f) {
//LOGD("Main", "DrawerBox()");
}
DrawerBox::~DrawerBox() {
//LOGD("Main", "~DrawerBox()");
if (bodyId.index1 != 0) b2DestroyBody(bodyId);
}
bool DrawerBox::init(int w, int h, int deg,
const bool dynamicFlg) {
// Pixel to Meter
const float mX = this->p2m(pos.x);
const float mY = this->p2m(pos.y) * -1.0f;
widthM = this->p2m(w);
heightM = this->p2m(h);
// Define the body
b2BodyDef bodyDef = b2DefaultBodyDef();
if (dynamicFlg) bodyDef.type = b2_dynamicBody;
bodyDef.position = (b2Vec2) {mX, mY};
bodyDef.rotation = b2MakeRot(DEG_TO_RAD * deg);
bodyId = b2CreateBody(worldId, &bodyDef);
// ShapeDef
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.isSensor = false;
shapeDef.enableContactEvents = true;// Important
shapeDef.userData = this;
// Polygon
b2Polygon polygon = b2MakeBox(widthM / 2, heightM / 2);
b2CreatePolygonShape(bodyId, &shapeDef, &polygon);
// Points
points.at(0).x = -w / 2;
points.at(0).y = -h / 2;
points.at(1).x = w / 2;
points.at(1).y = -h / 2;
points.at(2).x = w / 2;
points.at(2).y = h / 2;
points.at(3).x = -w / 2;
points.at(3).y = h / 2;
return true;
}
void DrawerBox::update(const float delay) {
// Draw
this->draw();
}
void DrawerBox::draw() {
// Rotation
const auto position = b2Body_GetPosition(bodyId);
const auto rotation = b2Body_GetRotation(bodyId);
const auto angle = b2Rot_GetAngle(rotation);
const float cosA = cosf(angle);
const float sinA = sinf(angle);
// Meter to Pixel
const float cX = this->m2p(position.x);
const float cY = this->m2p(position.y);
for (int i = 0; i < points.size(); i++) {
const float aX = points.at(i).x;
const float aY = points.at(i).y;
const int j = (i + 1) % points.size();
const float bX = points.at(j).x;
const float bY = points.at(j).y;
const float fX = aX * cosA - aY * sinA;
const float fY = aX * sinA + aY * cosA;
const float tX = bX * cosA - bY * sinA;
const float tY = bX * sinA + bY * cosA;
UtilCamera::getInstance()->drawLine(cX + fX, -(cY + fY),
cX + tX, -(cY + tY),
color, true);
}
}

基底クラスを継承して、円を描画するクラスを用意します
円を描画するクラス(ヘッダーファイルは省略)
DrawerCircle.cpp
#include "DrawerCircle.h"
DrawerCircle *DrawerCircle::create(const b2WorldId &worldId,
float x, float y,
int radius,
const bool dynamicFlg) {
// New
auto obj = new DrawerCircle(worldId, x, y);
if (obj && obj->init(radius, dynamicFlg)) return obj;
DX_SAFE_DELETE(obj);
return nullptr;
}
DrawerCircle::DrawerCircle(const b2WorldId &worldId,
float x, float y) :
DrawerBase(worldId, x, y), radiusM(0.0f) {
//LOGD("Main", "DrawerCircle()");
}
DrawerCircle::~DrawerCircle() {
//LOGD("Main", "~DrawerCircle()");
if (bodyId.index1 != 0) b2DestroyBody(bodyId);
}
bool DrawerCircle::init(int radius,
const bool dynamicFlg) {
// Pixel to Meter
const float mX = this->p2m(pos.x);
const float mY = this->p2m(pos.y) * -1.0f;
radiusM = this->p2m(radius);
// Define the body
b2BodyDef bodyDef = b2DefaultBodyDef();
if (dynamicFlg) bodyDef.type = b2_dynamicBody;
bodyDef.position = (b2Vec2) {mX, mY};
bodyId = b2CreateBody(worldId, &bodyDef);
// ShapeDef
b2ShapeDef shapeDef = b2DefaultShapeDef();
shapeDef.isSensor = false;
shapeDef.enableContactEvents = true;// Important
shapeDef.userData = this;
// Polygon
b2Circle circle = {0};
circle.center = (b2Vec2) {0.0f, 0.0f};
circle.radius = radiusM;
b2CreateCircleShape(bodyId, &shapeDef, &circle);
return true;
}
void DrawerCircle::update(const float delay) {
// Draw
this->draw();
}
void DrawerCircle::draw() {
// Rotation
const auto position = b2Body_GetPosition(bodyId);
const auto rotation = b2Body_GetRotation(bodyId);
const auto angle = b2Rot_GetAngle(rotation);
// Meter to Pixel
const float cX = this->m2p(position.x);
const float cY = this->m2p(position.y);
const float radiusP = this->m2p(radiusM);
const int segments = 12;
const float step = M_PI * 2.0f / segments;
for (int i = 0; i < segments; i++) {
float angle1 = step * i;
float angle2 = step * (i + 1);
float fX = cX + radiusP * cosf(angle1);
float fY = -(cY + radiusP * sinf(angle1));
float tX = cX + radiusP * cosf(angle2);
float tY = -(cY + radiusP * sinf(angle2));
UtilCamera::getInstance()->drawLine(fX, fY, tX, tY,
color, true);
}
}

実際に使ってみるとこういう感じになるかと思います
(重要な箇所だけ抜粋)
SceneBox2d.cpp
#include "SceneBox2d.h"
#include "box2d/box2d.h"
#include "box2d/collision.h"
#include "box2d/math_functions.h"
SceneBox2d::SceneBox2d(int dWidth, int dHeight) : SceneMain(dWidth, dHeight) {
LOGD("Main", "SceneBox2d()");
}
SceneBox2d::~SceneBox2d() {
LOGD("Main", "~SceneBox2d()");
// Delete
DX_SAFE_DELETE(camMan);
DX_SAFE_DELETE_VECTOR(bodies);
// Destroy
b2DestroyWorld(worldId);
}
bool SceneBox2d::init() {
LOGD("Main", "init");
// Center
const int gSize = UtilDebug::getInstance()->getGridSize();
const int cX = dWidth * 0.5f;
const int cY = dHeight * 0.5f;
// 省略
// Box2D
worldDef = b2DefaultWorldDef();
worldDef.gravity = (b2Vec2) {0.0f, -10.0f};
// World
worldId = b2CreateWorld(&worldDef);
const string result = b2World_IsValid(worldId) ? "Success!!" : "Failed...";
LOGD("Main", "Hello, Box2D: %s", result.c_str());
// 地面オブジェクト
const int deg = UtilMath::getInstance()->getRandom(-1, 1);
const auto ground = DrawerBox::create(
worldId, cX, cY, gSize * 24, gSize * 2, deg, false);
ground->setCameraFlg(true);
bodies.push_back(ground);
// 四角オブジェクトをx10
for (int i = 0; i < 10; i++) {
const int x = cX + UtilMath::getInstance()->getRandom(gSize * -4, gSize * 4);
const int y = cY - UtilMath::getInstance()->getRandom(gSize * 18, gSize * 50);
const auto box = DrawerBox::create(
worldId, x, y, gSize * 1, gSize * 2, 0, true);
box->setCameraFlg(true);
bodies.push_back(box);
}
// 円オブジェクトをx10
for (int i = 0; i < 10; i++) {
const int x = cX + UtilMath::getInstance()->getRandom(gSize * -4, gSize * 4);
const int y = cY - UtilMath::getInstance()->getRandom(gSize * 18, gSize * 50);
const auto circle = DrawerCircle::create(
worldId, x, y, gSize, true);
circle->setCameraFlg(true);
bodies.push_back(circle);
}
}
void SceneBox2d::update(const float delay) {
// Update Box2D
for (auto body: bodies) body->update(delay);// Update
b2World_Step(worldId, delay, 8);// Step
}
このスクラップは2日前にクローズされました