這次 test 採用 gtest 的 Test Fixtures,這樣就可以寫各式各樣類似的測試 (僅僅 time_step 會變)。
整個 code 很簡單:
#include <gtest/gtest.h>強力推薦大家使用 Google C++ Testing Framework. 接下來再寫幾個 acceptance tests,然後開始偷竊游戲物理設定。
#include "physics_simulation/box2d/box2d_service.h"
#include "physics_simulation/box2d/box2d_world.h"
#include "physics_simulation/box2d/box2d_body.h"
#include "physics_simulation/world_config.h"
#include "physics_simulation/body_config.h"
#include "physics_simulation/fixture_config.h"
#include "physics_simulation/polygon_shape_config.h"
#include <math.h>
namespace physics_simulation {
namespace box2d {
class VaryingFrictionTest : public testing::Test {
protected:
virtual void SetUp();
virtual void TearDown();
World* world_;
Body* box_[5];
Body* track_[3];
Body* ground_;
private:
void SetUpWorld();
void SetUpGround();
void SetUpTopTrack();
void SetUpMiddleTrack();
void SetUpBottomTrack();
void SetUpRightStopper();
void SetUpLeftStopper();
void SetUpFiveBoxes();
Body* stopper_[2];
};
void VaryingFrictionTest::SetUp() {
SetUpWorld();
SetUpGround();
SetUpTopTrack();
SetUpMiddleTrack();
SetUpBottomTrack();
SetUpRightStopper();
SetUpLeftStopper();
SetUpFiveBoxes();
}
void VaryingFrictionTest::TearDown() {
delete world_;
}
void VaryingFrictionTest::SetUpWorld() {
Service* service = new Box2dService();
WorldConfig config;
config.gravity.set(0.0f, -10.0f);
this->world_ = service->createWorld(config);
delete service;
}
void VaryingFrictionTest::SetUpGround() {
BodyConfig config;
this->ground_ = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsEdge(math::Vector2(-40.0f, 0.0f),
math::Vector2( 40.0f, 0.0f));
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->ground_->createFixture(fixture);
}
void VaryingFrictionTest::SetUpTopTrack() {
BodyConfig config;
config.position.set(-4.0f, 22.0f);
config.angle = -0.25f;
this->track_[0] = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[0]->createFixture(fixture);
}
void VaryingFrictionTest::SetUpMiddleTrack() {
BodyConfig config;
config.position.set(4.0f, 14.0f);
config.angle = 0.25f;
this->track_[1] = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[1]->createFixture(fixture);
}
void VaryingFrictionTest::SetUpBottomTrack() {
BodyConfig config;
config.position.set(-4.0f, 6.0f);
config.angle = -0.25f;
this->track_[2] = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsBox(13.0f, 0.25f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->track_[2]->createFixture(fixture);
}
void VaryingFrictionTest::SetUpRightStopper() {
BodyConfig config;
config.position.set(10.5f, 19.0f);
this->stopper_[0] = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsBox(0.25f, 1.0f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->stopper_[0]->createFixture(fixture);
}
void VaryingFrictionTest::SetUpLeftStopper() {
BodyConfig config;
config.position.set(-10.5f, 11.0f);
this->stopper_[1] = world_->createBody(config);
PolygonShapeConfig shape;
shape.setAsBox(0.25f, 1.0f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 0.0f;
this->stopper_[1]->createFixture(fixture);
}
void VaryingFrictionTest::SetUpFiveBoxes() {
PolygonShapeConfig shape;
shape.setAsBox(0.5f, 0.5f);
FixtureConfig fixture;
fixture.shape_config = &shape;
fixture.density = 25.0f;
const float friction[5] = { 0.75f, 0.5f, 0.35f, 0.1f, 0.0f };
for (int i = 0; i < 5; ++i) {
BodyConfig config;
config.type = BodyConfig::Dynamic;
config.position.set(-15.0f + 4.0f * i, 28.0f);
box_[i] = world_->createBody(config);
fixture.friction = friction[i];
box_[i]->createFixture(fixture);
}
}
namespace {
float dist(const Vector2& u, const Vector2& v) {
return Vector2(u.x - v.x, u.y - v.y).length();
}
} // namespace
TEST_F(VaryingFrictionTest, AfterOneMinute) {
const int steps = 60 * 60; // One minute
const float time_step = 1.0f/60.0f;
for (int i = 0; i < steps; ++i) {
world_->simulate(time_step);
}
// Box #0 and #1 are on the top track.
for (int i = 0; i < 2; ++i) {
EXPECT_LT(dist(box_[i]->position(), track_[0]->position()),
dist(box_[i]->position(), track_[1]->position()));
EXPECT_LT(dist(box_[i]->position(), track_[0]->position()),
dist(box_[i]->position(), track_[2]->position()));
}
// Box #2 is on the bottom track
EXPECT_LT(dist(box_[2]->position(), track_[2]->position()),
dist(box_[2]->position(), track_[1]->position()));
EXPECT_LT(dist(box_[2]->position(), track_[2]->position()),
dist(box_[2]->position(), track_[0]->position()));
// Box #3 is on the ground
EXPECT_FLOAT_EQ(0.51503909f, box_[3]->position().y);
// Box #4 is out of the screen
EXPECT_TRUE(box_[4]->position().length() > 2000.0f);
}
} // namespace box2d
} // namespace physics_simulation
沒有留言:
張貼留言