0.简介
这次来看step函数。
1.step开始
step函数里看起来如下的样子,当然我们只关注一块。
void World::Step(float dt)
{
float inv_dt = dt > 0.0f ? 1.0f / dt : 0.0f;
// 碰撞检测
BroadPhase();
...
}
BroadPhase函数是碰撞碰撞检测函数。具体讲解在代码注释
void World::BroadPhase()
{
//这是一个O(n^2)的循环
for (int i = 0; i < (int)bodies.size(); ++i)
{
//获取一个物体
Body* bi = bodies[i];
for (int j = i + 1; j < (int)bodies.size(); ++j)
{
//获取第二个物体
Body* bj = bodies[j];
//如果两个物体的质量倒数的0,就是两个质量无穷大的物体,不进行碰撞检测了
if (bi->invMass == 0.0f && bj->invMass == 0.0f)
continue;
//这里是创建一个值(val)和一个键(key)
//值中主要存储两个物体的指针和两个物体的碰撞信息
Arbiter newArb(bi, bj);
//键中存放的是两个物体的指针,以便用于哈希表查找的键
//而且为了避免(bi,bj),(bj,bi)不同,构造key的时候将指针值较小的放在前面
ArbiterKey key(bi, bj);
//arbiters里面主要存放两个物体的碰撞信息(存入哈希表中),
//arbiters是一个map,键是ArbiterKey,值是Arbiter
if (newArb.numContacts > 0)//当两个物体bi,bj有碰撞产生时
{
//这里先获取哈希表查找(bi,bj)键后的结果
ArbIter iter = arbiters.find(key);
if (iter == arbiters.end())//如果没找到对应的两个物体已有的碰撞
{
arbiters.insert(ArbPair(key, newArb));//将两个物体新的碰撞信息加入
}
else//如果找到对应的键
{
//更新键中的碰撞结果
iter->second.Update(newArb.contacts, newArb.numContacts);
}
}
else//如果两个物体没有碰撞,则删除哈希表中已有的记录
{
arbiters.erase(key);
}
}
}
}
ArbiterKey就是如下的一个小结构体。
struct ArbiterKey
{
ArbiterKey(Body* b1, Body* b2)
{
//永远让指针值小的在前
if (b1 < b2)
{
body1 = b1; body2 = b2;
}
else
{
body1 = b2; body2 = b1;
}
}
Body* body1;//物体1指针
Body* body2;//物体2指针
};
Arbiter中我有重大发现。其构造函数里有碰撞检测调用过程。
struct Arbiter
{
enum {MAX_POINTS = 2};
Arbiter(Body* b1, Body* b2);//构造函数里有碰撞检测过程
...
Body* body1;//物体1指针
Body* body2;//物体2指针
...
};
走进Arbiter的构造函数。
Arbiter::Arbiter(Body* b1, Body* b2)
{
//指针值较小的存储在body1中,和键中的对应上
//个人觉得这个类完全可以继承ArbiterKey,然后生成键和值的时候就不用
//分别构造两次了,只构造一次就能同时生成基类的键和子类值,body1和body2还可以复用
if (b1 < b2)
{
body1 = b1;
body2 = b2;
}
else
{
body1 = b2;
body2 = b1;
}
//碰撞检测函数,会返回碰撞点个数,contacts进去的指针,最后会获取具体碰撞点的信息
numContacts = Collide(contacts, body1, body2);
//两个物体之前的摩擦系数计算
friction = sqrtf(body1->friction * body2->friction);
}