Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5519854
  • 博文数量: 763
  • 博客积分: 12108
  • 博客等级: 上将
  • 技术积分: 15717
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-28 21:21
个人简介

业精于勤,荒于嬉

文章分类

全部博文(763)

文章存档

2018年(6)

2017年(15)

2016年(2)

2015年(31)

2014年(14)

2013年(87)

2012年(75)

2011年(94)

2010年(190)

2009年(38)

2008年(183)

2007年(28)

分类: C/C++

2011-01-26 15:58:08

2. Hello Box2D


2.1 创建一个世界


每个 Box2D 程序都将从一个世界对象(world object)的创建开始。这是一个管理内存,对象和模拟的
中心。
要创建一个世界对象,我们首先需要定义一个世界的包围盒。Box2D 使用包围盒来加速碰撞检测。尺
寸并不关键,但合适的尺寸有助于性能。这个包围盒过大总比过小好。
b2AABB worldAABB;
worldAABB.lowerBound.Set(-100.0f, -100.0f);
worldAABB.upperBound.Set(100.0f, 100.0f);
? 注意:worldAABB 应该永远比物体所在的区域要大,让 worldAABB 更大总比太小要好。如果一
个物体到达了 worldAABB 的边界,它就会被冻结并停止模拟。
接下来我们定义重力矢量。是的,你可以使重力朝向侧面(或者你只好转动你的显示器)。并且,我们
告诉世界(world)当物体停止移动时允许物体休眠。一个休眠中的物体不需要任何模拟。
b2Vec2 gravity(0.0f, -10.0f);
bool doSleep = true;
现在我们创建世界对象。通常你需要在堆(heap)上创建世界对象,并把它的指针保存在某一结构中。
然而,在这个例子中也可以在栈上创建。
b2World world(worldAABB, gravity, doSleep);

那么现在我们有了自己的物理世界,让我们再加些东西进去。


2.2 创建一个地面盒


物体通常由以下步骤来创建:
1. 使用位置(position),阻尼(damping)等定义一个物体
2. 使用世界对象创建物体
3. 使用几何结构,摩擦,密度等定义形状
4. 在物体上创建形状
5. 可选地调整物体的质量以和附加的形状相匹配
第一步,我们创建地面体。要创建它我们需要一个物体定义(body definition),通过物体定义我们来
指定地面体的初始位置。
b2BodyDef groundBodyDef;
groundBodyDef.position.Set(0.0f, -10.0f);
第二步,将物体定义传给世界对象来创建地面体。世界对象并不保存到物体定义的引用。地面体是作
为静态物体(static body)创建的,静态物体之间并没有碰撞,它们是固定的。当一个物体具有零质量的
时候 Box2D 就会确定它为静态物体,物体的默认质量是零,所以它们默认就是静态的。
b2Body* ground = world.CreateBody(&groundBodyDef);
第三步,我们创建一个地面的多边形定义。我们使用 SetAsBox 简捷地把地面多边形规定为一个盒子
(矩形)形状,盒子的中点就位于父物体的原点上。
b2PolygonDef groundShapeDef;
groundShapeDef.SetAsBox(50.0f, 10.0f);
其中,SetAsBox 函数接收了半个宽度和半个高度,这样的话,地面盒就是 100 个单位宽(x 轴)以及
20 个单位高(y 轴)。Box2D 已被调谐使用米,千克和秒来作单位,所以你可以用米来考虑长度。然而,
改变单位系统是可能的,随后的文档中会有讨论。
在第四步中,我们在地面体上创建地面多边形,以完成地面体。
groundBody->CreateShape(&groundShapeDef);
重申一次,Box2D 并不保存到形状或物体的引用。它把数据拷贝到 b2Body 结构中。
注意每个形状都必须有一个父物体,即使形状是静态的。然而你可以把所有静态形状都依附于单个静
态物体之上。这个静态物体之需求是为了保证 Box2D 内部的代码更具一致性,以减少潜在的 bug 数
量。
可能你已经注意到了,大部分 Box2D 类型都有一个 b2 前缀。这是为了降低它和你的代码之间名字冲

突的机会。


2.3 创建一个动态物体


现在我们已经有了一个地面体,我们可以使用同样的方法来创建一个动态物体。除了尺寸之外的主要
区别是,我们必须为动态物体设置质量性质。
首先我们用 CreateBody 创建物体。
b2BodyDef bodyDef;
bodyDef.position.Set(0.0f, 4.0f);
b2Body* body = world.CreateBody(&bodyDef);
接下来我们创建并添加一个多边形形状到物体上。注意我们把密度设置为 1,默认的密度是 0。并
且,形状的摩擦设置到了 0.3。形状添加好以后,我们就使用 SetMassFromShapes 方法来命令物体通
过形状去计算其自身的质量。这暗示了你可以给单个物体添加一个以上的形状。如果质量计算结果为 0,
那么物体会变成真正的静态。物体默认的质量就是零,这就是为什么我们无需为地面体调用
SetMassFromShapes 的原因。
b2PolygonDef shapeDef;
shapeDef.SetAsBox(1.0f, 1.0f);
shapeDef.density = 1.0f;
shapeDef.friction = 0.3f;
body->CreateShape(&shapeDef);
body->SetMassFromShapes();

这就是初始化过程。现在我们已经准备好开始模拟了。


2.4 模拟(Box2D 的)世界


我们已经初始化好了地面盒和一个动态盒。现在是让牛顿接手的时刻了。我们只有少数几个问题需要
考虑。
Box2D 中有一些数学代码构成的积分器(integrator),积分器在离散的时间点上模拟物理方程,它将
与游戏动画循环一同运行。所以我们需要为 Box2D 选取一个时间步,通常来说游戏物理引擎需要至少
60Hz 的速度,也就是 1/60 的时间步。你可以使用更大的时间步,但是你必须更加小心地为你的世界调
整定义。我们也不喜欢时间步变化得太大,所以不要把时间步关联到帧频(除非你真的必须这样做)。直截
了当地,这个就是时间步:
float32 timeStep = 1.0f / 60.0f;
除了积分器之外,Box2D 中还有约束求解器(constraint solver)。约束求解器用于解决模拟中的所有
约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另
一个。要得到良好的解,我们需要迭代所有约束多次。建议的 Box2D 迭代次数是 10 次。你可以按自己
的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的迭代会增加性能并降低精度,同样
地,更多的迭代会减少性能但提高模拟质量。这是我们选择的迭代次数:
int32 iterations = 10;
注意时间步和迭代数是完全无关的。一个迭代并不是一个子步。一次迭代就是在时间步之中的单次遍
历所有约束,你可以在单个时间步内多次遍历约束。
现在我们可以开始模拟循环了,在游戏中模拟循环应该并入游戏循环。每次循环你都应该调用
b2World::Step,通常调用一次就够了,这取决于帧频以及物理时间步。
这个 Hello World 程序设计得非常简单,所以它没有图形输出。胜于完全没有输出,代码会打印出动
态物体的位置以及旋转角度。Yay!这就是模拟 1 秒钟内 60 个时间步的循环:
for (int32 i = 0; i < 60; ++i)
{
world.Step(timeStep, iterations);
b2Vec2 position = body->GetPosition();
float32 angle = body->GetAngle();
printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);

}


2.5 清理工作


当一个世界对象超出它的作用域,或通过指针将其 delete 时,所有物体和关节的内存都会被释放。

这能使你的生活变得更简单。然而,你应该将物体,形状或关节的指针都清零,因为它们已经无效了。


2.6 关于 Testbed


一旦你征服了 HelloWorld 例子,你应该开始看 Box2D 的 testbed 了。testbed 是一个单元测试框
架以及演示环境,这是一些它的特点:
? 可移动和缩放的摄像机
? 鼠标拣选动态物体的形状
? 可扩展的测试集
? 通过图形界面选择测试,调整参数,以及设置调试绘图
? 暂停和单步模拟

? 文字渲染


在 testbed 中有许多 Box2D 的测试用例,以及框架本身的实例。我鼓励你通过研究和修改它来学习
Box2D。
注意:testbed 是使用 freeglut 和 GLUI 写成的,testbed 本身并不是 Box2D 库的一部分。Box2D
本身对于渲染是无知的,就像 HelloWorld 例子一样,使用 Box2D 并不一定需要渲染。
阅读(2988) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~