1、创建一个静态物体
创建一个静态物体应该很简单,在头文件生命一下要创建新物体的函数,然后在cpp文件中实现它即可。
具体的时候先过程,首先要用createbody函数创建一个物体,然后定义一个b2bodydef变量,指定一下这个变量的type还有position。这样的话一个最简单的静态物体就算是创建好了。
2、物体的相互作用
但是我们虽然创建了两个物体但是在运行的时候发现依然没有看到静止的物体挡住了动态运动的物体,这就是两个物体并没有发生相互作用。
为了让两个物体发生相互作用,我们要设置一个fixture
2. Body: Box2d 中的 Body 没有形状大小,不能碰撞,只具备质量(由 Fixture 的 shape 和 density 决定)、速度、位置这几个基本属性; Body 可以接收力和冲量的作用; 可以附着 Fixture ,附着后才具备形状大小,可以碰撞反弹 Body 有 3 种: static: 没有速度,不接受力和冲量的作用; dynamic: 有速度,可以接受力和冲量的作用; kinematic: 有速度,不接受力和冲量的作用。与 dynamic 碰撞不会改变原速度,与 static 碰撞不会有反应 创建 Body: b2BodyDef myBodyDef; myBodyDef.type = b2_dynamicBody; myBodyDef.position.Set(0, 20); m_body = m_world->CreateBody(&myBodyDef); 3. Fixture: Fixture 描述了物体的 形状、密度、弹性、摩擦因数; 两个物体发生碰撞时的反应由其 Fixture 决定; 一个 Body 可以有多个 Fixture ,Body 的重心受多个 Fixture 的影响; Fixture 中的 shape、destiny 等都是以标准单位 米、千克每平方来作为单位的,设定的时候可以参考实际的情形; Fixture 有四种 shape : b2PolygonShape: 多边形 b2CircleShape: 圆形 b2EdgeShape: 线 b2ChainShape: 链(几条线连在一起) Friction 摩擦因数: friction 值的范围为 0 到 1,为 0 表示完全没有摩擦,为 1 并不意味着不存在滑动; 当两个物体发生摩擦时,摩擦的大小取决于比较小的 friction Restitution 弹性: restitution 值的范围为 0 到 1, 为 0 表示完全没有弹性,碰撞时所有的能量将全部被反弹回去; 当两个物体发生碰撞时,碰撞的结果取决于比较大的 restitution 创建 Friction: b2PolygonShape polygonShape; polygonShape.SetAsBox(1,1); b2FixtureDef myFixtureDef; myFixtureDef.shape = &polygonShape; myFixtureDef.density = 1; myFixtureDef.friction = 0; // 摩擦因数为 0 myFixtureDef.restitution = 1; // 弹性因数为 1 m_body->CreateFixture(&myFixtureDef);
上面的代码片段还有解释应该能说明为什么要给一个物理设置fixture,body看起来是很单一的,如果想让他实现真实物理世界中的一些特性就要设置fixture。
fixture主要是设置物体的一些性质,和之前创建物体时候的bodydef的概念类似。
在用b2PolygonShape shape;这句话指定了物体的形状是多边形之后,还要对应的设置这个物体的位置。利用的就是setasbox.SetAsBox函数接收半个宽度和半个高度作为参数,也就是说,设置出来的这个物体的尺寸是里面的参数的两倍大小。
void HelloWorld::addrect() { b2BodyDef def; b2FixtureDef fixdef; b2PolygonShape shape; b2Body *b = word->CreateBody(&def); auto sprite = Sprite::create(); def.position = b2Vec2(3,5); def.type = b2_dynamicBody; shape.SetAsBox(0.5,0.5); fixdef.density = 1; fixdef.friction = 0.3; fixdef.shape = &shape; b->CreateFixture(&fixdef); addChild(sprite); sprite->setTextureRect(Rect(0,0,0.5*2*RATIO,0.5*2*RATIO)); b->SetUserData(sprite); } void HelloWorld::addground() { b2BodyDef def; b2PolygonShape shape; def.position = b2Vec2(400/RATIO,0); shape.SetAsBox(400/RATIO,0.5); def.type = b2_staticBody; b2Body * body = word->CreateBody(&def); b2FixtureDef fixdef; fixdef.density = 1; fixdef.friction = 0.3; fixdef.shape = &shape; body->CreateFixture(&fixdef); }
两个函数,上面的一个是创建动态的物体然后下落,下面这个函数是创建一个地板,是静态物体。之所是设置fixtrue就是为了能让物体之间产生相互的作用。将物体的属性完备一些,就可以出现一些真实物理世界的情况。
3、创建漂浮的物体
创建漂浮的物体其实也很简单,只不过是改变一下这个物体的类型为b2_kinematicBody即可。漂浮物体和静止物体是不一样的,静止物体是绝对不动的。漂浮物体的物体是不受物理世界的重力控制的。如果想让漂浮物体真正起到漂浮的效果要怎么办呢,很简单,给这个物体设置一个初速度就可以了。
def.linearVelocity = b2Vec2(1,0);设置一个只沿着x 轴方向的初速度。
4、物体的碰撞检测
一般来说,侦听一个事件都需要一个侦听器.
b2ContactListener 这个类主要就是用来监听一些物体之间的接触的。通过实现
b2ContactListener 你就可以收到接触数据。接触监听器支持几种事件: 开始(begin),结束(end), 求解前(pre-solve), 求解后(post-solve)。
Begin事件
当两个fixture开始有重叠时,事件会被触发。传感器和非传感器都会触发这事件。这事件只能在时间步内(译注: 也就是b2World::step函数内部)发生。
End事件
当两个fixture不再重叠时,事件会被触发。传感器和非传感器都会触发这事件。当一个body被摧毁时,事件也有可能被触发。所以这事件也有可能发生在时间步之外。
Pre-Solve事件
在碰撞检测之后,但在碰撞求解之前,事件会被触发。这样可以给你一个机会,根据当前情况来决定是否使这个接触失效。 举个例子,在回调中使用b2Contact::SetEnabled(false),你就可以实现单侧碰撞的功能。每次碰撞处理时,接触会重新生效,所以你在每一个时间步 中都应禁用那个接触。由于连续碰撞检测,pre-solve事件在单个时间步中有可能发生多次。
为了测试,我准备用begin来检验这个监听器的效果。
动态的物体会下落,那么下落在地板上的时候,肯定会发生接触,这样就可以用这个类的一些方法来检测了。SetContactListener利用这个函数创建一个监听器,参数就是我们当前的这个类,this。之后便可以重新实现void HelloWorld::BeginContact(b2Contact* contact).
重新实现如下
void HelloWorld::BeginContact(b2Contact* contact) { if(contact->GetFixtureA()->GetBody() == groundbody||contact->GetFixtureB()->GetBody() == groundbody) { log("have a body in ground"); } }
contact对象可以获取到接触的两个fixture进而获取到他们的实体,如果有一个是地板的话,那么就说明那个自由下落的动态物体和地板发生碰撞了,这样就显示一个消息