创建图腾破坏者的关卡


现在你有能力创建你的第一个游戏原型,我们将从创建图腾破坏者的级别开始。

为了展示我们所做事情的真实性,我们将流行的Flash游戏图腾破坏者的一关作为 我们模仿的对象。请看下面的截图:

这是图腾破坏者游戏原型的第一关,如果你仔细观察你会发现砖块的尺寸是30的倍 数。你知道这是什么原因吗?如果在你认真学习了前面的章节,你就会知道这是将米 和像素的转换所致。

作者创建游戏可能是直接使用米作为度量单位的,但是我们将坚持自己的选择使用像素作为度量单位。

目前,我们无需去担心怎样设置褐色和黑色的图腾颜色,我们只要想着再现图腾即可。

在我们开始编码之前,我将建议你创建几个方法,这样可以帮我们重用部分代码。别担心,没什么新的东西,我们只是稍微组织一下我们的脚本。

1、因此,我们将创建一个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);
}

2、然后,由于我们要创建很多的砖块,所以我强烈推荐用一个方法通过砖 块的位置和尺寸来创建砖块,所以下面的brick()方法的参数为:砖块原点 的水平和垂直坐标,宽度和高度。

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);
}

如果你看看代码就会发现没有什么新东西,但是我希望你能看看突出显示的那几行代码:

°  首先,被注释了的那行设置类型属性的代码, 因此目前我们创建的都 是static类型的刚体。当你在设置关卡的时候,使用static类型的刚体比 较好,一旦你满意你所设计的关卡时,可以将它们转变为dynamic类型 的刚体。static类型的刚体将帮助你查看每一个刚体的精确位置,避免 重叠或其它的设计错误。 


°  其次,在SetAsBox()方法中, 我们将砖块的宽高分别除以2再除以之前 的worldScale。无论它要的是砖块的半宽和半高,我这么做是想要用真 实的宽高像素来调用brick()方法,

3、 你的Main类的方法应该看起来向下面这样:

function main(){
world = new b2World(gravity, sleep);
debugDraw();
// level design goes here
setInterval(updateWorld, 1000 / 60);
}

现在Main()方法看起来简单清晰,那么我们可以通过调用brick()方法,一次一 块的来搭建我们的关卡。

并且,请注意我将重力(gravity)设置为(0,5)而不是作为小球下落时的真 实世界的重力。较弱的重力将会使图腾破坏和下落变得慢一些,从而产生更 好的效果。总之,这只是个与游戏设计的建议,而且你可以自由设置你自己 的重力。

4、现在,让我们回到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);
}

我们先搭建左边的基石砖块和右边的基石砖块,然后剩下的砖块从下向上一次堆放。

5、测试你的影片

完整源码在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对象和旋转的弧度。

1、应用上面的方法,在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度。

2、你可以将这四个变量作为参数传入SetAsOrientedBox()方法: 


polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle);

3、然后,照例我们要更新夹具的shape属性:

fixtureDef.shape = polygonShape;

4、那么,神奇的神奇的事情要发生了,我不用去创建一个新b2Body对象,我们 将夹具附加到已经存在的theIdol刚体上:

theIdol.CreateFixture(fixtureDef);

5、如果我们为交叉形状的另一个矩形应用相同的参数,我们需要改变一下boxAngle变量: 


boxAngle=Math.PI/4;

6、然后我们可以创建定向矩形,更新夹具的shape属性,然后添加它到theIdol刚 体上:

    polygonShape.SetAsOrientedBox(bW, bH, boxPos, boxAngle);
fixtureDef.shape = polygonShape;
theIdol.CreateFixture(fixtureDef);

7、最后,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);
}

8、测试影片,我们将看到神像与之前的图案比较相似了:

完整代码在demo2-6.html

现在,我们仍需要创建它的头部。

这次,你应该可以自己去创建它了吧。总而言之,它只是另一个复合刚体的定向矩形部件。我将向你展示另外一种方式,使用更加强大的方法创建一个多边形形状。


创建各种类型的凸多边形

Box2D允许你创建任何种类的多边形形状,只要多边形是凸多边形,这将意味着它拥 有的所有内角要小于180度,所以所有的顶点要远离中心,而且你要按顺时针顺序排 列它们。

1、首先,让我们创建一个向量(Vector)来储存所有的顶点: 


// 用多边形方式创建凸多边形
var vertices = new b2Vec2();

2、然后,我们将所有顶点作为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));

3、之前的几行代码表示的是神像的头部的四个顶点。现在让我们将向(vector) 变成多边形形状

polygonShape.SetAsVector(vertices, 4);

SetAsVector方法将任何顺时针方向的顶点向量(vector)变成一个多边形形 状。第二个参数只是代表需要的顶点数。

4、最后,和通常一样,你需要更新夹具的shape属性并将它添加到theIdol刚 体上 


fixtureDef.shape = polygonShape;
theIdol.CreateFixture(fixtureDef);

5、下面就是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);
}

6、测试影片然后你将在最后看到你完成的在图腾顶部的神像

7、这时,你只需要创建地面,它是一个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);
}

8、下面是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);
}

9、然后删除brick()方法内的注释行,将砖块设置为dynamic类型:

bodyDef.type = b2Body.b2_dynamicBody;

10、最后,我们将神像的也设置为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

HTML5之2D物理引擎 Box2D for javascript Games 系列 第三部分之创建图腾破坏者的关卡的更多相关文章

  1. HTML5之2D物理引擎 Box2D for javascript Games 系列 翻外篇--如何结合createJS应用box2d.js

    太久没有更新了,新年回来工作,突然有收到网友的邮件提问,居然还有人在关注,惭愧,找了下电脑上还有一点儿存着,顺便先发这一个番外篇吧,好歹可以看到真实的效果,等我考完英语,一定会更新下一章," ...

  2. HTML5之2D物理引擎 Box2D for javascript Games 系列 第一部分

    我要的是能在H5页面上跑的javascript版的Box2D啊!!! 最近想学习Javascript版本的Box2D JS物理引擎,无奈搜了半天也没找到相对比较系统的资料 官方网站也只是简单的介绍,A ...

  3. HTML5之2D物理引擎 Box2D for javascript Games 系列 第二部分

    这是系列第二部分,之前部分在本博客中找 源码demo存放在https://github.com/willian12345/Box2D-for-Javascript-Games 向世界添加刚体 刚体(B ...

  4. Matter.js – 你不能错过的 2D 物理引擎

    Matter.js 是一个 JavaScript 2D 刚体物理引擎的网页.Matter.Engine 模块包含用于创建和操作引擎的方法.这个引擎是一个管理更新和渲染世界的模拟控制器. Matter. ...

  5. cocos2dx-3.x物理引擎Box2D介绍

    理引擎 Cocos2d-x引擎内置了两种物理引擎,它们分别是Box2D和Chipmunk,都是非常优秀的2D物理引擎,而且x引擎将它们都内置在SDK中.Box2D使用较为广泛,在这里选择Box2D来进 ...

  6. 制作简单的2D物理引擎(零)

    最近发现了Github上的开源物理引擎项目Matter.js,对它很感兴趣,发现源码并不算长,算上注释大约1万行左右,值得剖析一番.Matter.js实现一个最小化的2D物理引擎,性能不错,故打算用C ...

  7. 制作简单的2D物理引擎(一)——动力学基础

    一切的基础 点 在二维平面中,点$P$就是坐标$(x,y)$,点集就是一系列坐标的集合$\{P_1,P_2,...,P_n\}$,不过这个集合是有序的(顺时针). 向量 加减运算 $$\vec{P}\ ...

  8. VUE,使用物理引擎Box2D设计类愤怒小鸟的击球游戏--基本架构设置

  9. HTML5游戏2D开发引擎

    1.PixiJS(基于webGl和canvas) 官网:http://www.pixijs.com/ github(star:20672):https://github.com/pixijs/pixi ...

随机推荐

  1. jsp之session对象

    jsp之session对象:一:概念session对象可以在应用程序的web页面之间跳转时保存用户的信息,使整个用户会话一直存在,直到关闭浏览器或是销毁session.session的生命周期:20~ ...

  2. (二)一起学 Java Collections Framework 源码之 AbstractCollection

    . . . . . 目录 (一)一起学 Java Collections Framework 源码之 概述(未完成) (二)一起学 Java Collections Framework 源码之 Abs ...

  3. POJ 3261 出现至少K次的可重叠最长子串

    题意就是给一列数字,求最长的一个子串,并且满足子串在原数串中出现至少K次,子串可以重叠. 解法是将问题转为判定性问题,二分子串的长度,判定是否满足重复至少K次.判定方法是经典的根据子串长度将Heigh ...

  4. Java 工具类—日期获得,随机数,系统命令,数据类型转换

    package tems; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Calendar; ...

  5. 详解常用的gulp命令

    gulp.js是一款自动化构建工具,我们经常使用它在开发过程自动执行常见的任务.gulp.js 是基于 Node.js 构建的,利用 Node.js,可以快速构建项目. 由于gulp使用基于node, ...

  6. JavaEE开发之SpringMVC中的自定义消息转换器与文件上传

    上篇博客我们详细的聊了<JavaEE开发之SpringMVC中的静态资源映射及服务器推送技术>,本篇博客依然是JavaEE开发中的内容,我们就来聊一下SpringMVC中的自定义消息转发器 ...

  7. PHP三维数组拼装

    foreach ($records as $k => $v) { foreach ($records as $m => $n) { if ($v['days'] == $n['days'] ...

  8. Numpy的使用

    Numpy的主要功能: 可以观察以上的规律,会发现,代码类型的简写,计量都是以8作为起始1的. # -*- coding: utf-8 -*- #向量相加-Python def pythonsum(n ...

  9. zabbix监控docker

    [toc] 1.下载模版 然后把模版放到/usr/local/lib/zabbix/agent下 github地址内含监控模版 2.修改 zabbix-agentd 配置文件 vim /usr/loc ...

  10. dotNet Linux 学习记录 - Jexus寄宿WCF服务

    让WCF运行在Linux上(寄宿于服务器程序) WCF介绍请自行 bing 搜索 使用的开发工具为vs2017,系统为 Ubuntu16.04 服务器软件为Jexus ( 详情请看:  Jexus官网 ...