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)

第10章 世界(World Class) 关于 b2World类包含物体和关节。它管理着模拟的方方面面,并允许异步查询(就像AABB查询和光线投射)。 你与Box2D的大部分交...
  • deruiyu93
  • deruiyu93
  • 2014年01月16日 08:45
  • 390

Box2D v2.1.0 用户手册

Box2D v2.1.0 用户手册 版权 © 2007-2010 Erin Catto 第01章 导言(Introduction) 第02章 Hello Box2D 第03章 公共模块(...
  • henren555
  • henren555
  • 2013年10月12日 09:47
  • 489

Box2D v2.1.0用户手册(12)——其它

第12章 调试绘图(Debug Drawing) 实现 b2DebugDraw 可得到物理世界的细部图,这里是可用的实体: •                    形状轮廓 •...
  • linmy1211
  • linmy1211
  • 2014年09月05日 15:30
  • 636

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

第02章 Hello Box2D Box2D的发布包中有个Hello World程序。程序创建了一个大大的地面盒(ground box)和一个小小的动态盒(dynamic box)。...
  • linmy1211
  • linmy1211
  • 2014年09月05日 11:35
  • 582

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

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

Box2D v2.1.0用户手册(11)——杂项(Loose Ends)

第11章 杂项(Loose Ends) 11.1 隐式摧毁 Box2D没有使用引用计数。你摧毁了body后,它就确实不存在了。访问指向已摧毁body的指针,会导致未定义的行...
  • linmy1211
  • linmy1211
  • 2014年09月05日 15:26
  • 482

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

第03章 公共模块(Common) 3.1 关于 公共模块包含了配置(Settings),内存管理(memory management)和矢量数学(vector m...
  • linmy1211
  • linmy1211
  • 2014年09月05日 14:21
  • 464

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

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

Box2D v2.1.0用户手册(7)——物体(Bodies)

第07章 物体(Bodies) 7.1 关于 物体具有位置和速度。你可以将力(forces), 扭矩(torques),冲量(impulses)应用到物体上。 物体可以是静...
  • linmy1211
  • linmy1211
  • 2014年09月05日 14:52
  • 699

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

第09章 接触(Contacts) 9.1 关于 接触(contact)是由 Box2D 创建的用于管理fixture间碰撞的对象。接触有不同的种类,它们都派生自 b2Co...
  • linmy1211
  • linmy1211
  • 2014年09月05日 15:16
  • 526
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Box2D v2.1.0用户手册(10)——世界(World Class)
举报原因:
原因补充:

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