Box2D v2.1.0用户手册(10)——世界(World Class)

转载 2014年09月05日 15:24:04

第10章 世界(World Class)


关于

b2World类包含物体和关节。它管理着模拟的方方面面,并允许异步查询(就像AABB查询和光线投射)。 你与Box2D的大部分交互都将通过 b2World 对象来完成。


创建和摧毁world

创建一个world十分的简单。你只需提供一个重力矢量,和一个布尔量去指定物体是否可以休眠。 通常你会使用new和delete去创建和摧毁一个world。

b2World* myWorld = newb2World(gravity, doSleep);

... do stuff ...

delete myWorld;


使用World

world类含有用于创建和摧毁物体与关节的工厂函数, 已在物体和关节的章节中讨论过。 在这里我们讨论b2World的其它交互。


模拟(Simulation)

世界类用于驱动模拟。你需要指定一个时间步和一个速度及位置的迭代次数。例如:

float32 timeStep = 1.0f / 60.f;

int32 velocityIterations = 10;

int32 positionIterations = 8;

myWorld->Step(timeStep,velocityIterations, positionIterations);

在时间步完成之后,你可以调查物体和关节的信息。最经常的情况是你会获取物体的位置,这样你才能更新你的角色并渲染它们。 你可以在游戏循环的任何地方执行时间步,但你应该注意事情发生的先后顺 序。例如,如果你想要在一帧(frame)中得到新物体的碰撞结果,你必须在时间步之前创建物体。

正如之前我在 HelloWorld 教程中说明的,你需要使用一个固定的时间步。使用大一些的时间步你可 以在低帧率的情况下提升性能。 但通常情况下你应该使用一个不大于 1/30 秒 的时间步。1/60 的时间步通常会呈现一个高质量的模拟。

迭代次数控制了约束求解器会遍历多少次世界中的接触以及关节。更多的迭代总能产生更好的模拟, 但不要使用小频率大迭代数。60Hz和10次迭代远好于30Hz和20次迭代。

时间步之后,你应该清除任何施加到物体之上的力。使用b2World::ClearForces可以完成。

myWorld->ClearForces();



探测世界(Exploring the World)

世界是物体和关节的容器。你可以获取世界中所有物体和关节并遍历它们。例如, 这段代码会唤醒世界中的所有物体:

for (b2Body* b = myWorld->GetBodyList();b; b = b->GetNext())

{

    b->WakeUp();

}

不幸的是真实的程序可能很复杂。例如,下面的代码是有错误的:

for (b2Body* b =myWorld->GetBodyList(); b; b = b->GetNext())

{

    GameActor* myActor = (GameActor*)b->GetUserData();

    if (myActor->IsDead())

    {

        myWorld->DestroyBody(b);// 错误: 现在GetNext会返回无用信息(garbage)

    }

}

在物体摧毁之前一切都很顺利。一旦物体摧毁了, 它的next指针就变得非法。所以 b2Body::GetNext() 就会返回无用信息。 解决方法是在物体摧毁之前拷贝next指针。

b2Body* node =myWorld->GetBodyList();

while (node)

{

    b2Body* b = node;

    node = node->GetNext();

    

    GameActor* myActor = (GameActor*)b->GetUserData();

    if (myActor->IsDead())

    {

        myWorld->DestroyBody(b);

    }

}

这能安全地摧毁当前物体。然而,你可能想要调用一个游戏的函数来摧毁多个物体,这时你需要十分小心。 解决方案取决于具体应用, 但为求方便,在此我给出一种解决这问题的方法:

b2Body* node =myWorld->GetBodyList();

while (node)

{

    b2Body* b = node;

    node = node->GetNext();

    

    GameActor* myActor =(GameActor*)b->GetUserData();

    if (myActor->IsDead())

    {

        bool otherBodiesDestroyed =GameCrazyBodyDestroyer(b);

        if (otherBodiesDestroyed)

        {

            node =myWorld->GetBodyList();

        }

    }

}

很明显要保证这个能正确工作, GameCrazyBodyDestroyer对它都摧毁了什么必须要诚实。


AABB查询(AABB Queries)

有时你需要得出一个区域内的所有fixture。b2World类为此使用了broad-phase数据结构,提供了一个 log(N) 的快速方法。你提供一个世界坐标的AABB和b2QueryCallback的一个实现。只要fixture的AABB和需查询的AABB有重合,world类就会调用你的b2QueryCallback类。返回true表示要继续查询,否则就返回false。例如,下面的代码找到所有大致与指定AABB相交的fixtures并唤醒所有关联的物体。

class MyQueryCallback : publicb2QueryCallback

{

public:

    bool ReportFixture(b2Fixture*fixture)

    {

        b2Body* body =fixture->GetBody();

        body->WakeUp();

        

        // 返回true,继续查询

        return true;

    }

};

 

...

 

MyQueryCallback callback;

b2AABB aabb;

aabb.lowerBound.Set(-1.0f, -1.0f);

aabb.upperBound.Set(1.0f, 1.0f);

myWorld->Query(&callback,aabb);

你不能假定回调函数会以固定的顺序执行。


光线投射(Ray Casts)

你可以使用光线投射去做现场(line-of-site)检查, 开枪扫射等等。通过实现一个回调类,并提供一个开始点和结束点,你就可以执行光线投射。只要fixture被光线穿过,world就会调用你提供的类。回调时会传递fixture,交点,单位法向量,和光线通过的分数距离(fractional distance along the ray)。你不能假定回调会以固定的顺序执行。

通过返回fraction, 你可以控制光线投射是否继续执行。返回的fraction为0,表示应该结束光线投射。fraction为1,表示投射应该继续执行,并且没有和其它形状相交。如果你返回参数列表中传近来的fraction, 表示光线会被裁剪到当前的和形状的相交点。这样通过返回适当的fraction值,你可以投射任何形状,投射所有形状,或者只投射最接近的形状。

另外你可以返回fraction为-1,去过虑fixture。这样光线投射会继续执行,并表现得似乎fixture根本就存在。

(译注:关于fraction的含义,可以看第04章的注释)

这里是个例子:

// This class captures the closesthit shape.

class MyRayCastCallback : publicb2RayCastCallback

{

public:

    MyRayCastCallback()

    {

        m_fixture = NULL;

    }

    

    float32 ReportFixture(b2Fixture*fixture, const b2Vec2& point,

                constb2Vec2& normal, float32 fraction)

    {

        m_fixture = fixture;

        m_point = point;

        m_normal = normal;

        m_fraction = fraction;

        return fraction;

    }

    

    b2Fixture* m_fixture;

    b2Vec2 m_point;

    b2Vec2 m_normal;

    float32 m_fraction;

};

 

MyRayCastCallback callback;

b2Vec2 point1(-1.0f, 0.0f);

b2Vec2 point2(3.0f, 1.0f);

myWorld->RayCast(&callback,point1, point2);

 

注意

由于舍入误差,光线投射可能会通过在静态环境中的多边形之间的细小裂缝。如果这不是您的应用程序中的可接受的,请稍微扩大您的多边形。

力和冲量(Forces and Impulses)

你可以将力,扭矩,及冲量应用到物体上。当应用一个力或者冲量时,你需要提供一个在世界坐标下的受力点。这经常导致相对于质心,会有个扭矩。

void ApplyForce(const b2Vec2&force, const b2Vec2& point);

void ApplyTorque(float32 torque);

void ApplyLinearImpulse(constb2Vec2& impulse, const b2Vec2& point);

void ApplyAngularImpulse(float32impulse);

应用力,扭矩或冲量会唤醒物体。有时这是不合需求的。例如,你可能想要应用一个固定的力,并允许物体休眠来提升性能。这时,你可以使用这样的代码:

if (myBody->IsAwake() == true)

{

    myBody->ApplyForce(myForce,myPoint);

}

坐标转换(Coordinate Transformations)

body类包含一些工具函数,它们可以帮助你在局部和世界坐标系之间转换点和向量。如果你不了解这些概念,请看 Jim Van Verth 和 Lars Bishop 的“游戏和交互应用的数学基础(Essential Mathematics for Games and Interactive Applications)”。这些函数都很高效(当inline时)。

b2Vec2 GetWorldPoint(constb2Vec2& localPoint);

b2Vec2 GetWorldVector(constb2Vec2& localVector);

b2Vec2 GetLocalPoint(constb2Vec2& worldPoint);

b2Vec2 GetLocalVector(constb2Vec2& worldVector);

列表(Lists)

你可以遍历一个物体的fixture, 主要用途是帮助你访问fixture中的用户数据。

for (b2Fixture* f =body->GetFixtureList(); f; f = f->GetNext())

{

    MyFixtureData* data =(MyFixtureData*)f->GetUserData();

    ... do something with data ...

}

你也可以用类似的方法遍历物体的关节列表。

body也提供了访问相关contact的列表。你可以用来得到当前contact的信息。但使用时请小心,因为前一个时间步存在的contact,可能并不包含在当前列表中。


转载:http://blog.csdn.net/complex_ok/article/details/6730791

相关文章推荐

Box2D v2.1.0用户手册翻译 - 第10章 世界(World Class)

内容很多摘自 Aman JIANG(江超宇)翻译的Box2D v2.0.1 用户手册 第10章 世界(World Class) 关于 b2World...

Box2D v2.1.0用户手册(6)——夹具(Fixtures)

第06章 夹具(Fixtures) 6.1 关于 回想一下,形状并不知道物体的存在,可以独立使用。因此Box2D需要提供b2Fixture类,用于将形状附加到物体上。 fi...

Box2D v2.1.0用户手册(3)——公共模块(Common)

第03章 公共模块(Common) 3.1 关于 公共模块包含了配置(Settings),内存管理(memory management)和矢量数学(vector m...

Box2D v2.1.0用户手册(9)——接触(Contacts)

第09章 接触(Contacts) 9.1 关于 接触(contact)是由 Box2D 创建的用于管理fixture间碰撞的对象。接触有不同的种类,它们都派生自 b2Co...

Box2D v2.1.0用户手册(1)——导言(Introduction)

第01章 导言(Introduction) 1.1 关于 Box2D是个二维刚体仿真库, 用于编写游戏。程序员可以使用它, 让游戏中的物体运动起来更真实, 让游戏世界更具交互性。以...

Box2D v2.1.0用户手册(8)——关节(Joints)

第08章 关节(Joints) 8.1 关于 关节用于把物体约束到世界,或约束到其它物体上。在游戏中, 典型例子有木偶, 跷跷板和滑轮。用不同的方式将关节结合起来使用, 可...

Box2D v2.1.0用户手册(2)——Hello Box2D

第02章 Hello Box2D Box2D的发布包中有个Hello World程序。程序创建了一个大大的地面盒(ground box)和一个小小的动态盒(dynamic box)。...

Box2D v2.1.0用户手册翻译 - 第08章 关节(Joints)

第08章 关节(Joints) 8.1 关于 关节用于把物体约束到世界,或约束到其它物体上。在游戏中, 典型例子有木偶, 跷跷板和滑轮。用不同的方式将关节结合起来使用,...

Box2D v2.1.0用户手册翻译 - 第12, 13, 14章

内容很多摘自 Aman JIANG(江超宇)翻译的Box2D v2.0.1 用户手册 第12章 调试绘图(Debug Drawing) 实现 b2De...

Box2D v2.1.0用户手册翻译 - 第06章 夹具(Fixtures)

内容很多摘自 Aman JIANG(江超宇)翻译的Box2D v2.0.1 用户手册 第06章 夹具(Fixtures) 6.1 关于 回想...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Box2D v2.1.0用户手册(10)——世界(World Class)
举报原因:
原因补充:

(最多只允许输入30个字)