如今你有能力建立你的第一个游戏原型,咱们将从建立图腾破坏者的级别开始。html
为了展现咱们所作事情的真实性,咱们将流行的Flash游戏图腾破坏者的一关做为 咱们模仿的对象。请看下面的截图: git
这是图腾破坏者游戏原型的第一关,若是你仔细观察你会发现砖块的尺寸是30的倍 数。你知道这是什么缘由吗?若是在你认真学习了前面的章节,你就会知道这是将米 和像素的转换所致。github
做者建立游戏多是直接使用米做为度量单位的,可是咱们将坚持本身的选择使用像素做为度量单位。canvas
目前,咱们无需去担忧怎样设置褐色和黑色的图腾颜色,咱们只要想着再现图腾便可。学习
在咱们开始编码以前,我将建议你建立几个方法,这样能够帮咱们重用部分代码。别担忧,没什么新的东西,咱们只是稍微组织一下咱们的脚本。测试
一、所以,咱们将建立一个debugDraw()方法,它将处理全部与调试绘图编码
function debugDraw(){ var debugDraw = new b2DebugDraw(); debugDraw.SetSprite(document.getElementById("canvas").getContext("2d")); debugDraw.SetDrawScale(worldScale); debugDraw.SetFillAlpha(0.5); debugDraw.SetFlags(b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit); world.SetDebugDraw(debugDraw); }
二、而后,因为咱们要建立不少的砖块,因此我强烈推荐用一个方法经过砖 块的位置和尺寸来建立砖块,因此下面的brick()方法的参数为:砖块原点 的水平和垂直坐标,宽度和高度。spa
function brick(px, py, w, h){ var bodyDef = new b2BodyDef(); bodyDef.position.Set(px/worldScale, py/worldScale); //bodyDef.type = b2Body.b2_dynamicBody; var polygonShape = new b2PolygonShape(); polygonShape.SetAsBox(w/2/worldScale, h/2/worldScale); var fixtureDef = new b2FixtureDef(); fixtureDef.shape = polygonShape; fixtureDef.density = 2; fixtureDef.restitution = .4; fixtureDef.friction = .5; var theBrick = world.CreateBody(bodyDef); theBrick.CreateFixture(fixtureDef); }
若是你看看代码就会发现没有什么新东西,可是我但愿你能看看突出显示的那几行代码: debug
° 首先,被注释了的那行设置类型属性的代码, 所以目前咱们建立的都 是static类型的刚体。当你在设置关卡的时候,使用static类型的刚体比 较好,一旦你满意你所设计的关卡时,能够将它们转变为dynamic类型 的刚体。static类型的刚体将帮助你查看每个刚体的精确位置,避免 重叠或其它的设计错误。 设计
° 其次,在SetAsBox()方法中, 咱们将砖块的宽高分别除以2再除以以前 的worldScale。不管它要的是砖块的半宽和半高,我这么作是想要用真 实的宽高像素来调用brick()方法,
三、 你的Main类的方法应该看起来向下面这样:
function main(){ world = new b2World(gravity, sleep); debugDraw(); // level design goes here setInterval(updateWorld, 1000 / 60); }
如今Main()方法看起来简单清晰,那么咱们能够经过调用brick()方法,一次一 块的来搭建咱们的关卡。
而且,请注意我将重力(gravity)设置为(0,5)而不是做为小球下落时的真 实世界的重力。较弱的重力将会使图腾破坏和下落变得慢一些,从而产生更 好的效果。总之,这只是个与游戏设计的建议,并且你能够自由设置你本身 的重力。
四、如今,让咱们回到Main()方法中:
function main(){ world = new b2World(gravity, sleep); debugDraw(); brick(275,435,30,30); brick(365,435,30,30); brick(320,405,120,30); brick(320,375,60,30); brick(305,345,90,30); brick(320,300,120,60); setInterval(updateWorld, 1000 / 60); }
咱们先搭建左边的基石砖块和右边的基石砖块,而后剩下的砖块从下向上一次堆放。
五、测试你的影片
完整源码在demo2-4.html中查看
我想你会为你的测试成功而感到很是的开心。正如你学习搭建你的第一个图腾那 样,咱们准备将黄金神像放到图腾的顶部。在咱们添加地面和改变图腾刚体为dynamic类型以前,我但愿你思考一下黄金神 像。 假使咱们想要给黄金神像一个形状,而这个形状是不一样于矩形和圆形的形状,这将会怎样呢?
黄金神像在图腾破坏者中是主要角色,咱们不能用一个矩形来表明它或者不然诅咒的图腾将会永远困扰着咱们。
我想象出了下面的图形:
这就我说的黄金神像,就是咱们将要在Box2D中建立的物体。
上图的左边是神像刚体的轮廓,而后右边是完成的神像轮廓。
首先你看到的神像是由不止一个刚体组合而成的一个复杂刚体。记住Box2D只能接受 凸多边形。和图腾砖块只是单个的堆叠不一样,咱们须要经过某种方法合并全部的神像 组成对象。
首先,咱们将从建立一个垂直的矩形开始,这个咱们已经知道怎样建立了,咱们将把 它的代码放在Main()方法中最后一块图腾砖块以后。
function main(){ world = new b2World(gravity, sleep); debugDraw(); brick(275,435,30,30); brick(365,435,30,30); brick(320,405,120,30); brick(320,375,60,30); brick(305,345,90,30); brick(320,300,120,60); idol(320, 242); setInterval(updateWorld, 1000 / 60); }
下面的idol()方法是咱们建立神像的方法:
function idol(px, py){ var bodyDef = new b2BodyDef(); bodyDef.position.Set(px/worldScale, py/worldScale); //bodyDef.type = b2Body.b2_dynamicBody; var polygonShape = new b2PolygonShape(); polygonShape.SetAsBox(5/worldScale, 20/worldScale); var fixtureDef = new b2FixtureDef(); fixtureDef.shape = polygonShape; fixtureDef.density = 1; fixtureDef.restitution = .4; fixtureDef.friction = .5; var theIdol = world.CreateBody(bodyDef); theIdol.CreateFixture(fixtureDef); }
目前,咱们只添加了一个矩形形状,就和砖块同样,因此这些代码无需说明。
测试影片,你将会看到神像的刚体。
完整源码在demo2-5.html中查看
第二部分,咱们将建立一个交叉的形状。这个交叉的形状是由两个矩形组成,可是 此次他们分别要顺时针和逆时针旋转45度。
你将在下面学到建立定向的矩形形状。
建立定向矩形形状,我将使用b2PolygonShape类中和SetAsBox()方法类似的 SetAsOrientedBox()加强方法。 参数是矩形的宽和高,矩形的中心定义是一个b2Vec2对象和旋转的弧度。
一、应用上面的方法,在idol()方法中按照下面的步骤操做:
var bW = 5/worldScale; var bH = 20/worldScale; var boxPos = new b2Vec2(0, 10/worldScale);// 可使用矩形内的相对位置 var boxAngle = -Math.PI / 4;
前两行代码,咱们定义了矩形的尺寸,和咱们刚刚建立的矩形同样。
让咱们来看看第三行,在这里咱们定义了位置,你可能会有疑惑。第一个神 像的组件矩形的中心为(320,242)像素,因此为何我要将第二个神像矩形 的位置设置为(0,10)?不是应该放置在第一块神像组件矩形的附近吗? 这是你须要学习复合对象神奇的地方。如今,咱们不须要定义绝对位置,而是定义一个相对第一个神像组件矩形的位置。因此,这将意味着,矩形将放置在刚体中心偏下的位置。最后一行就是指定旋转的弧度,逆时针45度。
二、你能够将这四个变量做为参数传入SetAsOrientedBox()方法:
polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle);
三、而后,照例咱们要更新夹具的shape属性:
fixtureDef.shape = polygonShape;
四、那么,神奇的神奇的事情要发生了,我不用去建立一个新b2Body对象,咱们 将夹具附加到已经存在的theIdol刚体上:
theIdol.CreateFixture(fixtureDef);
五、若是咱们为交叉形状的另外一个矩形应用相同的参数,咱们须要改变一下boxAngle变量:
boxAngle=Math.PI/4;
六、而后咱们能够建立定向矩形,更新夹具的shape属性,而后添加它到theIdol刚 体上:
polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef);
七、最后,idol()方法将看起来和下面的代码片断同样:
function idol(px, py){ var bodyDef = new b2BodyDef(); bodyDef.position.Set(px/worldScale, py/worldScale); //bodyDef.type = b2Body.b2_dynamicBody; var polygonShape = new b2PolygonShape(); polygonShape.SetAsBox(5/worldScale, 20/worldScale); var fixtureDef = new b2FixtureDef(); fixtureDef.shape = polygonShape; fixtureDef.density = 1; fixtureDef.restitution = .4; fixtureDef.friction = .5; var theIdol = world.CreateBody(bodyDef); theIdol.CreateFixture(fixtureDef); // 建立定向矩形 var bW = 5/worldScale; var bH = 20/worldScale; var boxPos = new b2Vec2(0, 10/worldScale);// 可使用矩形内的相对位置 var boxAngle = -Math.PI / 4; // 左倾矩形 polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef); // 右倾矩形 boxAngle = Math.PI / 4; polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef); }
八、测试影片,咱们将看到神像与以前的图案比较类似了:
完整代码在demo2-6.html
如今,咱们仍须要建立它的头部。
此次,你应该能够本身去建立它了吧。总而言之,它只是另外一个复合刚体的定向矩形部件。我将向你展现另一种方式,使用更增强大的方法建立一个多边形形状。
Box2D容许你建立任何种类的多边形形状,只要多边形是凸多边形,这将意味着它拥 有的全部内角要小于180度,因此全部的顶点要远离中心,并且你要按顺时针顺序排 列它们。
一、首先,让咱们建立一个向量(Vector)来储存全部的顶点:
// 用多边形方式建立凸多边形 var vertices = new b2Vec2();
二、而后,咱们将全部顶点做为b2Vec2对象并顺时针顺序推入向量(vertices)中, 并为b2Vec2对象指派顶点相对神像刚体的中心的坐标位置。
var vertices = new Box2D.NVector(); vertices.push(new b2Vec2(-15/worldScale,-25/worldScale)); vertices.push(new b2Vec2(0,-90/worldScale)); vertices.push(new b2Vec2(15/worldScale, -25/worldScale)); vertices.push(new b2Vec2(0,-10/worldScale));
三、以前的几行代码表示的是神像的头部的四个顶点。如今让咱们将向(vector) 变成多边形形状
polygonShape.SetAsVector(vertices, 4);
SetAsVector方法将任何顺时针方向的顶点向量(vector)变成一个多边形形 状。第二个参数只是表明须要的顶点数。
四、最后,和一般同样,你须要更新夹具的shape属性并将它添加到theIdol刚 体上
fixtureDef.shape = polygonShape;
theIdol.CreateFixture(fixtureDef);
五、下面就是idol()方法看起来的样子:
function idol(px, py){ var bodyDef = new b2BodyDef(); bodyDef.position.Set(px/worldScale, py/worldScale); bodyDef.type = b2Body.b2_dynamicBody; var polygonShape = new b2PolygonShape(); polygonShape.SetAsBox(5/worldScale, 20/worldScale); var fixtureDef = new b2FixtureDef(); fixtureDef.shape = polygonShape; fixtureDef.density = 1; fixtureDef.restitution = .4; fixtureDef.friction = .5; var theIdol = world.CreateBody(bodyDef); theIdol.CreateFixture(fixtureDef); // 建立定向矩形 var bW = 5/worldScale; var bH = 20/worldScale; var boxPos = new b2Vec2(0, 10/worldScale);// 可使用矩形内的相对位置 var boxAngle = -Math.PI / 4; // 左倾矩形 polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef); // 右倾矩形 boxAngle = Math.PI / 4; polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef); // 用多边形方式建立凸多边形 var vertices = new Box2D.NVector(); vertices.push(new b2Vec2(-15/worldScale,-25/worldScale)); vertices.push(new b2Vec2(0,-90/worldScale)); vertices.push(new b2Vec2(15/worldScale, -25/worldScale)); vertices.push(new b2Vec2(0,-10/worldScale)); polygonShape.SetAsVector(vertices, 4); fixtureDef.shape = polygonShape; theIdol.CreateFixture(fixtureDef); }
六、测试影片而后你将在最后看到你完成的在图腾顶部的神像
七、这时,你只须要建立地面,它是一个static类型的矩形刚体
function main(){ world = new b2World(gravity, sleep); debugDraw(); brick(275,435,30,30); brick(365,435,30,30); brick(320,405,120,30); brick(320,375,60,30); brick(305,345,90,30); brick(320,300,120,60); idol(320, 242); floor(); setInterval(updateWorld, 1000 / 60); }
八、下面是floor()方法的定义:
function floor(){ var bodyDef = new b2BodyDef(); bodyDef.position.Set(320/worldScale, 465/worldScale); var polygonShape = new b2PolygonShape(); polygonShape.SetAsBox(320/worldScale, 15/worldScale); var fixtureDef = new b2FixtureDef(); fixtureDef.shape = polygonShape; fixtureDef.restitution = .4; fixtureDef.friction = .5; var theFloor = world.CreateBody(bodyDef); theFloor.CreateFixture(fixtureDef); }
九、而后删除brick()方法内的注释行,将砖块设置为dynamic类型:
bodyDef.type = b2Body.b2_dynamicBody;
十、最后,咱们将神像的也设置为dynamic类型 idol()方法内
bodyDef.type = b2Body.b2_dynamicBody;
正如本章开始时所说的,你在Box2D中建立一个真实的图腾破坏者关卡已经完成
完整代码请查看demo2-7
概述
你刚刚学习的是本书中最重要的章节之一,在这里你学习了怎样建立刚体而后
使用它们去设计成功游戏的关卡,例如图腾破坏者。
为了习惯使用Box2D的刚体,我建议你建立更多的图腾破坏者(Totem Destroyer)的关卡或者一些红砖移除(Red Remover)或者愤怒的小鸟(Angry Birds)的关卡。总之,它只是一个简单的形状。
本文相关代码请在
https://github.com/willian12345/Box2D-for-Javascript-Games
注:转载请注明出处博客园:sheldon-二狗-偷饭猫(willian12345@126.com)
https://github.com/willian12345