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

相關文章
相關標籤/搜索