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

 

我要的是能在H5页面上跑的javascript版的Box2D啊!!!

最近想学习Javascript版本的Box2D JS物理引擎,无奈搜了半天也没找到相对比较系统的资料javascript

官方网站也只是简单的介绍,API还引导向了FLASH AS3脚本。html

 

我要的是能在H5页面上跑的javascript版本的教程啊!!!前端

 

后来搜出了一本中文版Box2D for Flash Games,脚本是AS3版本的书。是由天地会(昵称:鲁邦三世)翻译的java

看,书封面git

 

没有Javascript版本的啊。点解?(υ◉ω◉υ)github

 

So... 我感受上帝选中了我⋋(◍’Θ’◍)⋌算法

之前的我是AS3脚本程序猿出生, 那么惟有用我丢掉的几年AS3脚本经验把它改写成Javascript版本的了,谁让我如今写的是Javascript呢。chrome

看…我作的封面浏览器

 

完美!!!函数

用Fireworks把原来的封面作成了javascript,可见我功力了吧,请叫我美工殿下!

我最先是作美工出生我会跟你说?(/ ̄(エ) ̄)/

 

好吧,那我就一边学,一边改为javascript版本了。

若是文章有侵权行为,那么,要么联系我删掉?

要么来告我,反正我也没钱(ミ ̄ー ̄ミ)

个人邮箱willian12345@126.com

 

本系列源码持续更新中,已寄存在github上

https://github.com/willian12345/Box2D-for-Javascript-Games

 

开始前的一些说明 

你一定假设你对javascript或者前端知识已经比较熟悉了,若是不熟悉的话你得先补一下前端知识再往下看

FLASH中的舞台对应网页中的Canvas

AS3 (ActionScript3.0)脚本对应网页中的Javascript

 

 

2D物理引擎中的一些概念名词翻译列表

rigid body :刚体


fixture :夹具


box :盒子或矩形

debug draw : 调试绘图

density :密度


friction :摩擦或摩擦系数

restitution : 恢复或恢复系数

force : 力或做用力


impulse : 冲量


linear velocity : 线速度或线速率

joint : 关节


motor : 马达


bullet : 子弹


sensor : 感应器

 

 

目录


 

 

 

第一章 Hello Box2D World

 

定义Box2D世界

运行模拟

概述

 

第二章 向世界添加刚体

 

你的第一个模拟----一个球落地

建立一个圆形形形状

建立夹具

使用调试绘制测试你的模拟

建立矩形形状

不一样的刚体类型----static, dynamic 和 kinematic

密度,摩擦和恢复

建立图腾破坏者的关卡

建立复合刚体

建立定向矩形

建立各类类型的凸多边形

概述

 

第三章 刚体的交互

 

经过鼠标点击选择并销毁刚体

将自定义属性指定到刚体上

遍历刚体并获取它的属性

概述

 

第四章 将力做用到刚体上

 

苹果掉落,修正

力,冲量和线速率

应用冲量来获得线速度

应用力来得到线速度

将力应用到真实的游戏中

物理游戏不仅是关于物理

放置物理小鸟

发射物理小鸟

概述

 

第五章 碰撞处理

 

碰撞检查

Box2D内建的碰撞监听

将碰撞开始和结束输出到输出窗口

检测当你要解决碰撞和当你解决了碰撞

在图腾破坏者中检测神像坠落地面

在愤怒的小鸟中销毁砖块并消灭小猪

概述

 

第六章 关节和马达

 

拾取并拖拽刚体—鼠标关节

让刚体之间保持给定的距离—距离关节

使刚体绕一个点旋转—旋转关节

当愤怒的小鸟碰见粉碎城堡

经过马达控制关节

经过键盘控制马达

让一些刚体不要发生碰撞—碰撞过滤

将它们放在一块儿

概述

 

第七章

使用你本身的图像资源代替调试绘图

概述

 

第八章 子弹和传感器

 

感觉隧道效应

阻止隧道效应—设置刚体为子弹

经过传感器检测接触,能够容许刚体重叠

 

第一章

一、Hello Box2D World

 


 

若是你想建立2D的物理驱动游戏与应用,Box2D是最佳的有效选择。

Box2D是一个 2D刚体的仿真库,它被使用在一些最成功的游戏上,例如在iPhone上的Angry Birds 和Tiny Wings或者在Flash上的Totem Destroyer和Red Remover。

Google一下它们,你 将会发现不少热心的评论。

在咱们进入Box2D世界以前,让我说明一下什么是刚体(Rigid Bodies)。

它是一块非 常坚硬的物质,任何方法都不能使它弯曲。不管你怎样用力去撞击(Hit)或投掷 (Throw)它,都没法改变它的形状。

在真实世界中,你能够将它的硬度想象成钻 石,甚至比钻石还要硬。也许你能够展开想象,假设它是来至外空间的一块不可变形 的物质。

Box2D只管理刚体(Rigid Bodies),从如今起,咱们将称它为刚体(Bodies)(这句 话中文是看不出什么不一样的,英文将Rigid Bodies简称为Bodies),不用小心,你将还 能够模仿不是刚性的材料,例如弹性球体。

让咱们看看,你将在本章节学习到那些知识:

• 安装Box2D


• 建立你的第一个Box2D世界


• 了解重力和睡眠刚体

• 运行程序,操做时间步和约束

本章结束后,你将能建立一个空的可运行的世界,在那里你能够搭建你那了不得的物理游戏。

 

 

在网页中安装Box2D


 

你能够从官方站点下载最新的Box2D.js版本或在个人github上直接下载合并好的源码 https://github.com/willian12345/Box2D-for-Javascript-Games/

 

新建一个demo1-1.html页面

下载到Box2D.js版本后放在网页同级目录或其它目录

根据目录在网页中直接引用

<script src="Box2d.js"></script>

可比在比FLASH简单多了

网页中再添加

<script type="text/javascript">

            function init(){

            function main(){

               console.log(Box2D);     

            }

 

            main();

         }

init();

</script>

 

测试一把

 

在浏览器中打开1.html

打开浏览器调试工具,推荐用chrome浏览器。

应该能看到调试器的Console内输出Object {Collision: Object, Common: Object, Dynamics: Object}

 

init()方法能够在onload时调用, init方法内再建一个main方法

模拟FLASH中自动调用的Main.as类。这里须要手动调用。固然你也随便建方法

 

完整代码在demo1-1.html中

 

第一步成功!

为了方便,在init方法一开始内能够添加如下代码,方便对象的使用

var b2Vec2 = Box2D.Common.Math.b2Vec2

   ,b2AABB = Box2D.Collision.b2AABB

   ,b2BodyDef = Box2D.Dynamics.b2BodyDef

   ,b2Body = Box2D.Dynamics.b2Body

   ,b2FixtureDef = Box2D.Dynamics.b2FixtureDef

   ,b2Fixture = Box2D.Dynamics.b2Fixture

   ,b2World = Box2D.Dynamics.b2World

   ,b2MassData = Box2D.Collision.Shapes.b2MassData

   ,b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape

   ,b2CircleShape = Box2D.Collision.Shapes.b2CircleShape

   ,b2DebugDraw = Box2D.Dynamics.b2DebugDraw

   ,b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef

   ;

 

先不用管具体作什么用,后面会一一用到的

 

当我给本节标题命名为Hello Box2D World时,我并不仅是为了建立另外一个"Hello World"程序,而是我想要介绍全部Box2D模拟和事件发生的环境:世界(World)。

世界(World)是模拟发生的舞台。你想要经过Box2D物理引擎控制的全部事物必须

在世界(World)中。幸运的是,Box2D世界(World)拥有足够大的空间来容纳你 须要的任何事物,因此你无需担忧世界(World)的边界(boundaries)。

你只须要 记住在电脑中的任何事物都要受到某种限制。因此,越大的世界(World),将会 消耗你的电脑越多的资源去管理它。

定义Box2D世界


与现实世界同样,Box2D世界(World)有重力(gravity),因此你须要先定义世界 重力(world gravity)。

1. 在你的main方法中,添加下面的一行代码:

var gravity = new b2Vec2(0,9.81);

这里将介绍咱们的第一个Box2D数据类型:b2Vec2。(注:在javascript中可没这个数据类型,把它当成一个对象就行了

b2Vec2是一个2D的纵向量数据类型,它将储存x和y矢量份量。如你所见,构 造函数有两个参数,都是数值,表明了x和y份量。经过这种方法咱们定义 gravity变量做为一个矢量,它有x=0(这意味着水平的重力)和y=-9.81(这意 味着近似的地球重力)。

物理学中说过,一个物体在地球表面自由下落的加速度近似为9.81m/s^2(米 每平方秒)也可写做"m/s/s"。因此,假设没有任何空气阻力,咱们在模拟一 个真实的世界(real-world)环境。解释物体下落的原理已经超越本书的范 围,可是你能够在Google或Wikipedia中搜索"equations for a falling body"去得到 更多的信息。

 

2. 你能够设置你的游戏为下面的这行代码:


var gravity = new b2Vec2(0,1.63);

你也能够将参数设置为(0,0)来模拟一个没有重力的环境:

var gravity = new b2Vec2(0,0); 

3. 咱们还须要告诉世界,当世界中的刚体静止时,能够容许他们进入睡眠状态,这样它们将不受做用力的影响。

一个睡眠的刚体无需模拟,它只是表示自 己的存在,并静止在它的位置上,不会对世界中的任何事物产生影响,容许 Box2D忽略它,并且所以会提高处理速度以及让咱们得到更好的性能。

因此推 荐可能时让刚体睡眠。 


4. 添加下面的一行,它只是一个简单的布尔(Boolean)变量定义:

var sleep = true; 


5. 最后,咱们准备建立咱们的第一个世界(world):


var world = new b2World(gravity,sleep); 


6.如今咱们有一个容器来管理全部的刚体而且执行咱们的动态模拟。

7.让咱们来简单的回顾一下以前的代码,此刻,你的代码应该看起以下面 所示: 

<script type="text/javascript">
         function init(){
            var b2Vec2 = Box2D.Common.Math.b2Vec2
            ,b2AABB = Box2D.Collision.b2AABB
            ,b2BodyDef = Box2D.Dynamics.b2BodyDef
            ,b2Body = Box2D.Dynamics.b2Body
            ,b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            ,b2Fixture = Box2D.Dynamics.b2Fixture
            ,b2World = Box2D.Dynamics.b2World
            ,b2MassData = Box2D.Collision.Shapes.b2MassData
            ,b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
            ,b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
            ,b2DebugDraw = Box2D.Dynamics.b2DebugDraw
            ,b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
            ;
            
            var gravity = new b2Vec2(0, 9.81);
            var sleep = true;
            var world = new b2World(gravity, sleep);
            function main(){
               
            }

            main();
         }
         init();
      </script>

如今你学习了怎样去建立并配置一个Box2D世界。让咱们来看看你将怎样在它里面实 现物理效果的模拟 。

 

 

 

运行模拟


你须要在每一帧都进行模拟,因此首先你须要一个监听来触发每一帧

1. 让咱们添加一点代码:

<script>
         function init(){
            var b2Vec2 = Box2D.Common.Math.b2Vec2
            ,b2AABB = Box2D.Collision.b2AABB
            ,b2BodyDef = Box2D.Dynamics.b2BodyDef
            ,b2Body = Box2D.Dynamics.b2Body
            ,b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            ,b2Fixture = Box2D.Dynamics.b2Fixture
            ,b2World = Box2D.Dynamics.b2World
            ,b2MassData = Box2D.Collision.Shapes.b2MassData
            ,b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
            ,b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
            ,b2DebugDraw = Box2D.Dynamics.b2DebugDraw
            ,b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
            ;

            var gravity = new b2Vec2(0, 9.81);
            var sleep = true;
            var world = new b2World(gravity, sleep);
            function main(){
               setInterval(updateWorld, 1000 / 60);
            }
            function updateWorld() {
               console.log("my awesome simulation runs here");
            }

            main();
         }
         init();
      </script>

 

没有什么新的,咱们只是添加了一个setInterval循环定时执行,可是咱们须要它有 序的运行updateWorld()方法中的模拟。

Box2D是经过模拟世界的离散时间步(step time)来进行模拟工做的。

这意味 着世界将在每个时间步被更新。

这将取决于咱们在模拟中所采用的时间 步。一般状况下,物理游戏的时间步为1/60秒。

 

2. 下面是updateWorld函数的第一行: 

var timeStep  = 1/30 

只是定义了时间步还不够。在每一步,每个物理实体(physic entity)根据 做用于自身的做用力来更新(不包括睡眠状态)。

处理这项任务的算法叫约 束解算器(constraint solver)。

 

它是基于循环每个约束而后解算来进的,一次一个,若是你想要学习更多的关于约束的知识,在google在搜 索"constraint algorithm"。

Where's the catch? 虽然单个约束能够被完美的解算,可是多个约束时,它 会搅乱以前已经解算的别的约束。

试想,当两个球移动的时候:在真实的世界,每个球的位置是在相同的时间更新。在电脑的模拟中,咱们须要经过循环来更新球的位置,而每次只能一个。试想一下for循环每次遍历更新一个球。只要球彼此间没有发生 相互做用,一切正常运行,可是如何第二个球撞击了第一个球,谁的位置被更新了?它们会重叠,这在刚体模拟中是不可能的事情。

经过取合适的近似值来解决这个问题,咱们须要循环全部的约束不止一次。如今问题是:咱们要循环多少次?

有两种约束解算器:速率约束解算器(velocity constraint solver)和位置约束解 算器(position constraint solver)。速率约束解算器依据它们的在世界中的冲量 来移动物理实体。位置约束解算器调整物理实体的位置避免重叠。

因此,越高的便利次数,将会有更精确的模拟,可是性能会更低。我设法处 理超过100个物理实体使用10次速率和位置遍历,虽然Box2D的做者推荐8次 速率和3次位置遍历。

这将由你来决定使用的值。与此同时,我将使用对两个约束解算器使用10次遍 历。 
咱们设置了两个新变量: 
 

var velIterations:int=10;

var posIterations:int=10;

注:先不用理解太深,反正我也没看懂,无论这个“约束”先 (=◎ω◎=)

最后咱们准备调用world变量的step方法来更新模拟。 


在updateWorld方法中使用world,咱们须要把world做为类变量声明,以下所 示:



<script>
         function init(){
            var b2Vec2 = Box2D.Common.Math.b2Vec2
            ,b2AABB = Box2D.Collision.b2AABB
            ,b2BodyDef = Box2D.Dynamics.b2BodyDef
            ,b2Body = Box2D.Dynamics.b2Body
            ,b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            ,b2Fixture = Box2D.Dynamics.b2Fixture
            ,b2World = Box2D.Dynamics.b2World
            ,b2MassData = Box2D.Collision.Shapes.b2MassData
            ,b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
            ,b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
            ,b2DebugDraw = Box2D.Dynamics.b2DebugDraw
            ,b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
            ;

            
            var world;
            function main(){
               var gravity = new b2Vec2(0, 9.81);
               var sleep = true;
               world = new b2World(gravity, sleep);

               setInterval(updateWorld, 1000 / 60);
            }
            function updateWorld() {
               var timeStep = 1/30;
               var velIterations = 10;
               var posIterations = 10;
               world.Step(timeStep,velIterations,posIterations);
            }

            main();
         }
         init();
      </script>

如今咱们有了咱们本身的世界配置,而后运行。不幸的是,这是一个很是空

  洞的世界,它的里面没有任何东西。因此在下一章,咱们将向世界中填充各

  种各样的物理实体。

 

最后还有一件事情,在每一步以后,你须要清除做用力,让模拟从 下一步再次开始。

你能够将这行world.ClearForces();代码添加到step方法以后;你最后的代 码以下所示: 

<script>
         function init(){
            var b2Vec2 = Box2D.Common.Math.b2Vec2
            ,b2AABB = Box2D.Collision.b2AABB
            ,b2BodyDef = Box2D.Dynamics.b2BodyDef
            ,b2Body = Box2D.Dynamics.b2Body
            ,b2FixtureDef = Box2D.Dynamics.b2FixtureDef
            ,b2Fixture = Box2D.Dynamics.b2Fixture
            ,b2World = Box2D.Dynamics.b2World
            ,b2MassData = Box2D.Collision.Shapes.b2MassData
            ,b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
            ,b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
            ,b2DebugDraw = Box2D.Dynamics.b2DebugDraw
            ,b2MouseJointDef =  Box2D.Dynamics.Joints.b2MouseJointDef
            ;

            
            var world;
            function main(){
               var gravity = new b2Vec2(0, 9.81);
               var sleep = true;
               world = new b2World(gravity, sleep);

               setInterval(updateWorld, 1000 / 60);
            }
            function updateWorld() {
               var timeStep = 1/30;
               var velIterations = 10;
               var posIterations = 10;
               world.Step(timeStep,velIterations,posIterations);
               world.ClearForces(); // 清除做用力
            }

            main();
         }
         init();
</script>

 

 

源码所有代码在github上的demo1-1.html中,可查看运行

概述

你刚刚学习了怎样为在网页中安装使用Box2D。将它包含到你的项目中并运行,重力规则模 拟,管理时间步以及约束解算器。

到如今为止,你的网页上其实并无显示任何东西。

你有一个空的世界,准备成为你游戏发生的容器。保存它而后在每个将来的项目中使用它!

 

 

 

 



注:转载请注明出处博客园:sheldon-二狗-偷饭猫(willian12345@126.com)

https://github.com/willian12345

相关文章
相关标签/搜索