您好,欢迎访问三七文档
Box2Dv2.0.1用户手册原文:Box2Dv2.0.2UserManual译者:AmanJIANG(江超宇),翻译信息。1.导言1.1关于Box2D是一个用于游戏的2D刚体仿真库。程序员可以在他们的游戏里使用它,它可以使物体的运动更加可信,让世界看起来更具交互性。从游戏的视角来看,物理引擎就是一个程序性动画(proceduralanimation)的系统,而不是由动画师去移动你的物体。你可以让牛顿来做导演。Box2D是用可移植的C++来写成的。引擎中定义的大部分类型都有b2前缀,希望这能消除它和你游戏引擎之间的名字冲突。1.2必备条件在此,我假定你已经熟悉了基本的物理学概念,例如质量,力,扭矩和冲量。如果没有,请先考虑读一下ChrisHecker和DavidBaraff(google这些名字)的那些教程,你不需要了解得非常细致,但他们可以使你很好地了解一些基本概念,以便你使用Box2D。Wikipedia也是一个极好的物理和数学知识的获取源,在某些方面它可能比google更有用,因为它的内容经过了精心的整理。这不是必要的,但如果你好奇Box2D内部是如何工作的,你可以看这些文档。因为Box2D是使用C++写成的,所以你应该具备C++程序设计的经验,Box2D不应该成为你的第一个C++程序项目。你应该已经能熟练地编译,链接和调试了。1.3核心概念Box2D中有一些基本的对象,这里我们先做一个简要的定义,在随后的文档里会有更详细的描述。刚体(rigidbody)一块十分坚硬的物质,它上面的任何两点之间的距离都是完全不变的。它们就像钻石那样坚硬。在后面的讨论中,我们用物体(body)来代替刚体。形状(shape)一块严格依附于物体(body)的2D碰撞几何结构(collisiongeometry)。形状具有摩擦(friction)和恢复(restitution)的材料性质。约束(constraint)一个约束(constraint)就是消除物体自由度的物理连接。在2D中,一个物体有3个自由度。如果我们把一个物体钉在墙上(像摆锤那样),那我们就把它约束到了墙上。这样,此物体就只能绕着这个钉子旋转,所以这个约束消除了它2个自由度。接触约束(contactconstraint)一个防止刚体穿透,以及用于模拟摩擦(friction)和恢复(restitution)的特殊约束。你永远都不必创建一个接触约束,它们会自动被Box2D创建。关节(joint)它是一种用于把两个或多个物体固定到一起的约束。Box2D支持的关节类型有:旋转,棱柱,距离等等。关节可以支持限制(limits)和马达(motors)。关节限制(jointlimit)一个关节限制(jointlimit)限定了一个关节的运动范围。例如人类的胳膊肘只能做某一范围角度的运动。关节马达(jointmotor)一个关节马达能依照关节的自由度来驱动所连接的物体。例如,你可以使用一个马达来驱动一个肘的旋转。世界(world)一个物理世界就是物体,形状和约束相互作用的集合。Box2D支持创建多个世界,但这通常是不必要的。2.HelloBox2D2.1创建一个世界每个Box2D程序都将从一个世界对象(worldobject)的创建开始。这是一个管理内存,对象和模拟的中心。要创建一个世界对象,我们首先需要定义一个世界的包围盒。Box2D使用包围盒来加速碰撞检测。尺寸并不关键,但合适的尺寸有助于性能。这个包围盒过大总比过小好。b2AABBworldAABB;worldAABB.lowerBound.Set(-100.0f,-100.0f);worldAABB.upperBound.Set(100.0f,100.0f);.注意:worldAABB应该永远比物体所在的区域要大,让worldAABB更大总比太小要好。如果一个物体到达了worldAABB的边界,它就会被冻结并停止模拟。接下来我们定义重力矢量。是的,你可以使重力朝向侧面(或者你只好转动你的显示器)。并且,我们告诉世界(world)当物体停止移动时允许物体休眠。一个休眠中的物体不需要任何模拟。b2Vec2gravity(0.0f,-10.0f);booldoSleep=true;现在我们创建世界对象。通常你需要在堆(heap)上创建世界对象,并把它的指针保存在某一结构中。然而,在这个例子中也可以在栈上创建。b2Worldworld(worldAABB,gravity,doSleep);那么现在我们有了自己的物理世界,让我们再加些东西进去。2.2创建一个地面盒物体通常由以下步骤来创建:1.使用位置(position),阻尼(damping)等定义一个物体2.使用世界对象创建物体3.使用几何结构,摩擦,密度等定义形状4.在物体上创建形状5.可选地调整物体的质量以和附加的形状相匹配第一步,我们创建地面体。要创建它我们需要一个物体定义(bodydefinition),通过物体定义我们来指定地面体的初始位置。b2BodyDefgroundBodyDef;groundBodyDef.position.Set(0.0f,-10.0f);第二步,将物体定义传给世界对象来创建地面体。世界对象并不保存到物体定义的引用。地面体是作为静态物体(staticbody)创建的,静态物体之间并没有碰撞,它们是固定的。当一个物体具有零质量的时候Box2D就会确定它为静态物体,物体的默认质量是零,所以它们默认就是静态的。b2Body*ground=world.CreateBody(&groundBodyDef);第三步,我们创建一个地面的多边形定义。我们使用SetAsBox简捷地把地面多边形规定为一个盒子(矩形)形状,盒子的中点就位于父物体的原点上。b2PolygonDefgroundShapeDef;groundShapeDef.SetAsBox(50.0f,10.0f);其中,SetAsBox函数接收了半个宽度和半个高度,这样的话,地面盒就是100个单位宽(x轴)以及20个单位高(y轴)。Box2D已被调谐使用米,千克和秒来作单位,所以你可以用米来考虑长度。然而,改变单位系统是可能的,随后的文档中会有讨论。在第四步中,我们在地面体上创建地面多边形,以完成地面体。groundBody-CreateShape(&groundShapeDef);重申一次,Box2D并不保存到形状或物体的引用。它把数据拷贝到b2Body结构中。注意每个形状都必须有一个父物体,即使形状是静态的。然而你可以把所有静态形状都依附于单个静态物体之上。这个静态物体之需求是为了保证Box2D内部的代码更具一致性,以减少潜在的bug数量。可能你已经注意到了,大部分Box2D类型都有一个b2前缀。这是为了降低它和你的代码之间名字冲突的机会。2.3创建一个动态物体现在我们已经有了一个地面体,我们可以使用同样的方法来创建一个动态物体。除了尺寸之外的主要区别是,我们必须为动态物体设置质量性质。首先我们用CreateBody创建物体。b2BodyDefbodyDef;bodyDef.position.Set(0.0f,4.0f);b2Body*body=world.CreateBody(&bodyDef);接下来我们创建并添加一个多边形形状到物体上。注意我们把密度设置为1,默认的密度是0。并且,形状的摩擦设置到了0.3。形状添加好以后,我们就使用SetMassFromShapes方法来命令物体通过形状去计算其自身的质量。这暗示了你可以给单个物体添加一个以上的形状。如果质量计算结果为0,那么物体会变成真正的静态。物体默认的质量就是零,这就是为什么我们无需为地面体调用SetMassFromShapes的原因。b2PolygonDefshapeDef;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的时间步。你可以使用更大的时间步,但是你必须更加小心地为你的世界调整定义。我们也不喜欢时间步变化得太大,所以不要把时间步关联到帧频(除非你真的必须这样做)。直截了当地,这个就是时间步:float32timeStep=1.0f/60.0f;除了积分器之外,Box2D中还有约束求解器(constraintsolver)。约束求解器用于解决模拟中的所有约束,一次一个。单个的约束会被完美的求解,然而当我们求解一个约束的时候,我们就会稍微耽误另一个。要得到良好的解,我们需要迭代所有约束多次。建议的Box2D迭代次数是10次。你可以按自己的喜好去调整这个数,但要记得它是速度与质量之间的平衡。更少的迭代会增加性能并降低精度,同样地,更多的迭代会减少性能但提高模拟质量。这是我们选择的迭代次数:int32iterations=10;注意时间步和迭代数是完全无关的。一个迭代并不是一个子步。一次迭代就是在时间步之中的单次遍历所有约束,你可以在单个时间步内多次遍历约束。现在我们可以开始模拟循环了,在游戏中模拟循环应该并入游戏循环。每次循环你都应该调用b2World::Step,通常调用一次就够了,这取决于帧频以及物理时间步。这个HelloWorld程序设计得非常简单,所以它没有图形输出。胜于完全没有输出,代码会打印出动态物体的位置以及旋转角度。Yay!这就是模拟1秒钟内60个时间步的循环:for(int32i=0;i60;++i){world.Step(timeStep,iterations);b2Vec2position=body-GetPosition();float32angle=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并不一定需要渲染。3.API设计3.1内存管理Box2D的许多设计决策都是为了能快速有效地使用内存。在本节我将论述Box2D如何和为什么要分配内存。Box2D倾向于分配大量的小对象(50-300字节左右)。这样通过malloc或new在系统的堆(heap)上分配内存就太低效,并且容易产生内存碎片。多数这些小型对象的生命期都很短暂,例如触点(contact),可能会维持几个时间步。所以我们需要为这些对象提供一个有效的分配器(allocator)。Box2D的解决方案是使用小型对象分配器(SOA),SOA维护了许多不定尺寸的可生长的
三七文档所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
本文标题:box2d教程
链接地址:https://www.777doc.com/doc-2903736 .html