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


 

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

最近想學習Javascript版本的Box2D JS物理引擎,無奈搜了半天也沒找到相對比較系統的資料

官方網站也只是簡單的介紹,API還引導向了FLASH AS3腳本。

 

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

 

后來搜出了一本中文版Box2D for Flash Games,腳本是AS3版本的書。是由天地會(昵稱:魯邦三世)翻譯的

看,書封面

 

沒有Javascript版本的啊。點解?(υ◉ω◉υ)

 

So... 我感覺上帝選中了我⋋(◍’Θ’◍)⋌

以前的我是AS3腳本程序猿出生, 那么唯有用我丟掉的幾年AS3腳本經驗把它改寫成Javascript版本的了,誰讓我現在寫的是Javascript呢。

看…我做的封面

 

完美!!!

用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內建的碰撞監聽

將碰撞開始和結束輸出到輸出窗口

檢測當你要解決碰撞和當你解決了碰撞

在圖騰破壞者中檢測神像墜落地面

在憤怒的小鳥中銷毀磚塊並消滅小豬

概述

 

第六章 關節和馬達

 

拾取並拖拽剛體—鼠標關節

讓剛體之間保持給定的距離—距離關節

使剛體繞一個點旋轉—旋轉關節

當憤怒的小鳥遇見粉碎城堡

通過馬達控制關節

通過鍵盤控制馬達

讓一些剛體不要發生碰撞—碰撞過濾

將它們放在一起

概述

 

第七章

使用你自己的圖像資源代替調試繪圖

概述

 

第八章 子彈和傳感器

 

感受隧道效應

阻止隧道效應—設置剛體為子彈

通過傳感器檢測接觸,可以允許剛體重疊

 

第一章

1、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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM