注意:以下内容纯属个人YY,切勿当真
1. box2d就是用来模拟现实的,为了限制模拟的范围,所以需要来个容器限制范围,所有有了 b2World,为了模拟现实中的重力,b2World可以设置重力和方向
为了能将现实世界的计算公式放到这个 虚拟的世界中,所以需要将屏幕里面的坐标转换为现实世界中的单位
2. 现实世界中的物体在世界坐标系中都有形状 大小 位置 角度 速度 摩擦力 质量 等属性.还有的东西不能进行移动,为了模拟这些东西
box 将这些物体分为 3种类型:
/// The body type.
/// static: zero mass, zero velocity, may be manually moved
/// kinematic: zero mass, non-zero velocity set by user, moved by solver
/// dynamic: positive mass, non-zero velocity determined by forces, moved by solver
enum b2BodyType
{
b2_staticBody = 0,
b2_kinematicBody,
b2_dynamicBody
// TODO_ERIN
//b2_bulletBody,
};
由于物体的形状和碰撞息息相关,不同的形状之前的碰撞都不一样,所以为了模拟这个,box2d里面定义了一些形状
这些形状为 b2ChainShape,b2CircleShape,b2EdgeShape,b2PolygonShape,
这些类都继承自 b2Shape,所以在创建物体的时候,一定要给物体定义一个形状。
3. 所以对于物体来讲,就要有 物体的类型、物体的形状、物体的物理属性(质量,密度,摩擦力)
在box2d中,表示物体基本类型定义的类为: b2BodyDef,看下其构造函数初始化了哪些东西:
/// This constructor sets the body definition default values.
b2BodyDef()
{
userData = NULL;
position.Set(0.0f, 0.0f);
angle = 0.0f;
linearVelocity.Set(0.0f, 0.0f);
angularVelocity = 0.0f;
linearDamping = 0.0f;
angularDamping = 0.0f;
allowSleep = true;
awake = true;
fixedRotation = false;
bullet = false;
type = b2_staticBody;
active = true;
gravityScale = 1.0f;
}
有了 b2BodyDef 这个物体类型的东西,我们就可以创建一个基本的对象了。
物体由b2World来创建:
/// Create a rigid body given a definition. No reference to the definition
/// is retained.
/// @warning This function is locked during callbacks.
b2Body* CreateBody(const b2BodyDef* def);
这样就创建了个物体。但是如何设置这物体的形状,和物理属性呢?
b2Body提供了一些方法:
/// Creates a fixture and attach it to this body. Use this function if you need
/// to set some fixture parameters, like friction. Otherwise you can create the
/// fixture directly from a shape.
/// If the density is non-zero, this function automatically updates the mass of the body.
/// Contacts are not created until the next time step.
/// @param def the fixture definition.
/// @warning This function is locked during callbacks.
b2Fixture* CreateFixture(const b2FixtureDef* def);
/// Creates a fixture from a shape and attach it to this body.
/// This is a convenience function. Use b2FixtureDef if you need to set parameters
/// like friction, restitution, user data, or filtering.
/// If the density is non-zero, this function automatically updates the mass of the body.
/// @param shape the shape to be cloned.
/// @param density the shape density (set to zero for static bodies).
/// @warning This function is locked during callbacks.
b2Fixture* CreateFixture(const b2Shape* shape, float32 density);
通过这方法,就能给物体设置其 外观,和物理属性.
外观就是 b2Shape,物理属性就由 b2FixtureDef 来定义
质量为0的东西 物理引擎不能动他.
//-----------------------------------------------------------------------------------------------------------
4. 来个例子:
a.创建一个 b2World,给世界设定一个重力大小和方向,b2World管理所有模拟的东西
// 创建一个 world
b2Vec2 gravity;
gravity.Set(0.5, -0.5);
world = new b2World(gravity);
b.把手机屏幕四周设置为"墙壁",
墙壁这东西,一般为静态物体,所以直接默认值就可以
b2BodyDef groundBodyDef;
创建墙壁
b2Body* groundBody = world->CreateBody(&groundBodyDef);
给这墙壁一个形状,让墙壁进行碰撞,然后再把这样的外观作用到物体上,由于有4个墙壁,所以作用4次
// Define the ground box shape.
b2EdgeShape groundBox;
// bottom
groundBox.Set(b2Vec2(VisibleRect::leftBottom().x/PTM_RATIO,VisibleRect::leftBottom().y/PTM_RATIO), b2Vec2(VisibleRect::rightBottom().x/PTM_RATIO,(VisibleRect::rightBottom().y)/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// top
groundBox.Set(b2Vec2(VisibleRect::leftTop().x/PTM_RATIO,VisibleRect::leftTop().y/PTM_RATIO), b2Vec2(VisibleRect::rightTop().x/PTM_RATIO,VisibleRect::rightTop().y/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// left
groundBox.Set(b2Vec2(VisibleRect::leftTop().x/PTM_RATIO,VisibleRect::leftTop().y/PTM_RATIO), b2Vec2(VisibleRect::leftBottom().x/PTM_RATIO,VisibleRect::leftBottom().y/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
// right
groundBox.Set(b2Vec2(VisibleRect::rightBottom().x/PTM_RATIO,VisibleRect::rightBottom().y/PTM_RATIO), b2Vec2(VisibleRect::rightTop().x/PTM_RATIO,VisibleRect::rightTop().y/PTM_RATIO));
groundBody->CreateFixture(&groundBox,0);
c. 添加一个球
球也是个物体,所以创建步骤和 墙壁类似
1.先来个b2BodyDef,为了让其能模拟,设置为 b2_dynamicBody 类型
b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
2. 创建球
b2Body *body = world->CreateBody(&bodyDef);
3. 给球加上外观,并且设置半径
b2CircleShape dynamicCircle;
dynamicCircle.m_radius = 22.0/PTM_RATIO;
4.定义这个球的物理属性 ,并作用在球上
b2FixtureDef fixtureDef;
fixtureDef.shape = &dynamicCircle;
fixtureDef.density = 1.0f;
fixtureDef.friction = 0.3f;
body->CreateFixture(&fixtureDef);
5.cocos2dx 定义个 CCPhysicsSprite 类,能让我们用一个sprite 和 这个 球关联起来
CCPhysicsSprite* sprite = CCPhysicsSprite::create("ball_2.png");
sprite->setB2Body(body);
sprite->setPTMRatio(PTM_RATIO);
sprite->setPosition(point);
addChild(sprite);
注意,创建了 CCPhysicsSprite后,一定先调用setB2Body(xxx)方法
并且还要设置PTM_RATIO,这个就是将 屏幕里面的坐标转换为现实世界中的单位的比例
例如:PTM_RATIO = 32, 则表示 32 个像素为1米
6. 进行模型,在游戏循环中调用 world的Step方法
void HelloWorld::update(float dt)
{
int velocityIterations = 8;
int positionIterations = 1;
world->Step(0.03,velocityIterations,positionIterations);
}
看看 b2World的Step方法说明
/// Take a time step. This performs collision detection, integration,
/// and constraint solution.
/// @param timeStep the amount of time to simulate, this should not vary.
/// @param velocityIterations for the velocity constraint solver.
/// @param positionIterations for the position constraint solver.
void Step( float32 timeStep,
int32 velocityIterations,
int32 positionIterations);
那个速度迭代次数和物理迭代次数就按推荐的来就ok了.