日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

2D物理引擎 Box2D for javascript Games 第七章 子弹和感应器

發(fā)布時間:2023/11/3 C# 101 coder
生活随笔 收集整理的這篇文章主要介紹了 2D物理引擎 Box2D for javascript Games 第七章 子弹和感应器 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

2D物理引擎 Box2D for javascript Games 第七章 子彈和感應(yīng)器

你知道 Box2D 可以在每一個時間步中管理剛體間的碰撞并決算它們。

總之,在憤怒的小鳥中制作攻城機(jī)器期間,發(fā)生了一些錯誤

你可能需要注意一下,有時拋射物會穿過城堡,忽略了碰撞。

這里發(fā)生了什么?

通常,Javascript 游戲運(yùn)行在 30 與 60 幀每秒之間,如果我們使世界的時間步與幀率同步,每一個時間步將代表 1/30 到 1/60 秒。

依賴時間步的模擬叫作離散模擬,這不同于真實(shí)的世界,在真實(shí)世界中事件的發(fā)生的是連續(xù)的,我們稱之為連續(xù)模擬

離散型模擬中,我們無法知道在時間中的第n步與第(n+1)步之間發(fā)生了什么

如果一個剛體的移動真的很快,那么他可以在小于一個時間步的時間之內(nèi)穿過另一個剛體,你會發(fā)現(xiàn)它在穿過的剛體的 另一邊了,而沒有發(fā)生碰撞。

這個現(xiàn)象叫作隧道效應(yīng) (tunneling),并且很自然的,我們想要阻止它的發(fā)生

在本章,你將學(xué)習(xí)兩種不同的方式去管理剛體間的接觸:

  • 設(shè)置剛體為子彈
  • 設(shè)置剛體為感應(yīng)器

通過本章的學(xué)習(xí),你將不會再對管理高速移動的剛體有任何問題

感受隧道效應(yīng)

Box2d 默認(rèn)的情況下對阻止隧道效應(yīng)做的很好,使用一個連續(xù)的碰撞檢測來計(jì)算離散型模擬。

不幸的是,處于性能相關(guān)的考慮,這種類型的碰撞檢測只應(yīng)用在 dynamic 類型剛體與 static 類型剛體之間的碰撞上。

這意味著,我們可以在兩個 dynamic 類型的剛體之間產(chǎn)生隧道效應(yīng)。

  1. 讓我們來看一下,下面的腳本:

     const stage = document.querySelector('#canvas');
     function main() {
          world = new b2World(gravity, sleep);
          debugDraw();
    
          var bodyDef = new b2BodyDef();
          bodyDef.position.Set(320 / worldScale, 470 / worldScale);
          var polygonShape = new b2PolygonShape();
          polygonShape.SetAsBox(320 / worldScale, 10 / worldScale);
          var fixtureDef = new b2FixtureDef();
          fixtureDef.shape = polygonShape;
          fixtureDef.density = 1;
          fixtureDef.restitution = 0.5;
          fixtureDef.friction = 0.5;
          var body = world.CreateBody(bodyDef);
          body.CreateFixture(fixtureDef);
    
          bodyDef.position.Set(600 / worldScale, 240 / worldScale);
          bodyDef.type = b2Body.b2_dynamicBody;
          polygonShape.SetAsBox(10 / worldScale, 220 / worldScale);
          var body2 = world.CreateBody(bodyDef);
          body2.CreateFixture(fixtureDef);
          
          bodyDef.position.Set(320 / worldScale, 455 / worldScale);
          polygonShape.SetAsBox(5 / worldScale, 5 / worldScale);
          var body3 = world.CreateBody(bodyDef);
          body3.CreateFixture(fixtureDef);
          body3.SetLinearVelocity(new b2Vec2(100, -10));
         
          stage.addEventListener('click', updateWorld);
       }
    

    這個腳本中沒有什么新的知識。

    它放置了三個剛體,分別叫作 body,body2,body3,它們分別代表了一個 static 類型的地面,一個 dynamic 類型的障礙物,以及一個 dynamic 類型的小子彈。

    如你所見,子彈以一個非??斓乃俣龋?00,-10)發(fā)射,然后 updateWorld() 方法將執(zhí)行世界的時間步,它不是在每一幀被調(diào)用,而是在每一次的鼠標(biāo)點(diǎn)擊時被調(diào)用。

    這樣可以使我們一步一步的來運(yùn)行模擬,如你想要的一樣慢,并且我們可以看到發(fā)生了什么。

  2. 測試網(wǎng)頁,然后多次點(diǎn)擊鼠標(biāo)。

    源碼: article/ch07/ch07-1.html

    發(fā)生了什么?拋物塊在沒有接觸到障礙物的情況下穿過了它。

    我們剛剛體驗(yàn)了隧道效應(yīng)。

    現(xiàn)在,讓我們做些什么來阻止它的發(fā)生吧!

阻止隧道效應(yīng)——設(shè)置剛體為子彈

因?yàn)檫B續(xù)的碰撞檢測使得隧道效應(yīng)無法在 static 類型的剛體上發(fā)生,

在某些情況下,我們也可以將這種方法應(yīng)用到 dynamic 類型的剛體上,通過設(shè)置它們?yōu)樽訌棧╞ullets)。

一個子彈(bullets)執(zhí)行連續(xù)的碰撞檢測,來檢測它與 static 類型的和 dynamic 類型的剛體之間的碰撞。

記住,如果你將所有的剛體都設(shè)置為子彈(bullets),你將會發(fā)現(xiàn)很高的性能消耗,所以這將由你在性能和精確度之間找到一個平衡點(diǎn)。

從我的經(jīng)驗(yàn)來看,只是一些被玩家或敵人發(fā)射的粒子和投射物被設(shè)置為子彈(bullets),通常游戲的角色不會移動的快到需要將它們設(shè)置為子彈(bullets)

  1. 在 main 函數(shù)中僅需要加入一句代碼:

    function main() {
        world = new b2World(gravity, sleep);
        debugDraw();
    
        var bodyDef = new b2BodyDef();
        bodyDef.position.Set(320 / worldScale, 470 / worldScale);
        var polygonShape = new b2PolygonShape();
        polygonShape.SetAsBox(320 / worldScale, 10 / worldScale);
        var fixtureDef = new b2FixtureDef();
        fixtureDef.shape = polygonShape;
        fixtureDef.density = 1;
        fixtureDef.restitution = 0.5;
        fixtureDef.friction = 0.5;
        var body = world.CreateBody(bodyDef);
        body.CreateFixture(fixtureDef);
    
        bodyDef.position.Set(600 / worldScale, 240 / worldScale);
        bodyDef.type = b2Body.b2_dynamicBody;
        polygonShape.SetAsBox(10 / worldScale, 220 / worldScale);
        var body2 = world.CreateBody(bodyDef);
        body2.CreateFixture(fixtureDef);
    
        bodyDef.position.Set(320 / worldScale, 455 / worldScale);
    
        // 加上這一句
        bodyDef.bullet = true;
    
        polygonShape.SetAsBox(5 / worldScale, 5 / worldScale);
        var body3 = world.CreateBody(bodyDef);
        body3.CreateFixture(fixtureDef);
        body3.SetLinearVelocity(new b2Vec2(100, -10));
        stage.addEventListener('click', updateWorld);
        // setInterval(updateWorld, 1000 / 60);
    }
    

    在剛體定義中將bullet屬性設(shè)置為true將對子彈進(jìn)行連續(xù)碰撞檢測。

    現(xiàn)在應(yīng)該會從障礙物上彈回。

  2. 測試網(wǎng)頁,來看看發(fā)生了什么。

    源碼: article/ch07/ch07-2.html

    看到了嗎?如你所見,接觸被決算,現(xiàn)在子彈被障礙物彈回。

  3. 將你的憤怒的小鳥模型中,通過拋擲器發(fā)射的投射物,應(yīng)用bullet屬性,然后將產(chǎn)生一個精確的模擬運(yùn)行

現(xiàn)在,讓我們來看看最后一個你在 Box2D 可以創(chuàng)建的特殊類型的剛體。

通過感應(yīng)器檢測接觸,可以允許剛體重疊

在你的游戲中,有時你可能需要兩個剛體就像沒有發(fā)生任何碰撞一樣重疊在一起,同時還能檢測到碰撞。

使用感應(yīng)器(sensor)可以實(shí)現(xiàn)這個功能;

感應(yīng)器:一個夾具可以在檢測到碰撞的情況下而不作出任何反應(yīng)。

你可以使用感應(yīng)器(sensor)創(chuàng)建剛體,所以你將可以在剛體間沒有任何物理觸點(diǎn)的情況下,知道它們之間發(fā)生的碰撞。

只要想象一下玩家控制的角色和一個開關(guān):你想要知道當(dāng)玩家控制的角色撞擊開關(guān)觸發(fā)一些事件,但是同時你不想開關(guān)響應(yīng)玩家的碰撞。

在最后的腳本中,我們將測試一個感應(yīng)器

  1. 和往常一樣,我們給剛體 userData 屬性中添加剛體的名字

    將 barrier 剛體設(shè)置為 static 類型并通過 isSensor 屬性定義的它的夾具為感應(yīng)器。

    function main() {
         world = new b2World(gravity, sleep);
         debugDraw();
    
         var bodyDef = new b2BodyDef();
         bodyDef.position.Set(320 / worldScale, 470 / worldScale);
         bodyDef.userData = "floor";
         var polygonShape = new b2PolygonShape();
         polygonShape.SetAsBox(320 / worldScale, 10 / worldScale);
         var fixtureDef = new b2FixtureDef();
         fixtureDef.shape = polygonShape;
         fixtureDef.density = 1;
         fixtureDef.restitution = 0.5;
         fixtureDef.friction = 0.5;
         fixtureDef.isSensor = true;
         var body = world.CreateBody(bodyDef);
         body.CreateFixture(fixtureDef);
    
         bodyDef.position.Set(600 / worldScale, 240 / worldScale);
         bodyDef.userData = "barrier";
         polygonShape.SetAsBox(10 / worldScale, 220 / worldScale);
         var body2 = world.CreateBody(bodyDef);
         body2.CreateFixture(fixtureDef);
    
         bodyDef.position.Set(320 / worldScale, 455 / worldScale);
         bodyDef.bullet = true;
         bodyDef.type = b2Body.b2_dynamicBody;
         bodyDef.userData = "bullet";
         polygonShape.SetAsBox(5 / worldScale, 5 / worldScale);
         fixtureDef.isSensor = false;
         var body3 = world.CreateBody(bodyDef);
         body3.CreateFixture(fixtureDef);
         body3.SetLinearVelocity(new b2Vec2(100, -10));
         // 鼠標(biāo)多次點(diǎn)擊后查看效果
         stage.addEventListener('click', updateWorld);
     }
    

    為什么我們要將 barrier 設(shè)置為 static 類型呢?

    因?yàn)樗且粋€感應(yīng)器,它的碰撞將不會被決算,所以如果我們設(shè)置它為 dynamic 類型,它將不會和地面發(fā)生碰撞,所以沒有支撐物,將會一直下落。

    將它設(shè)置為 static 類型可以確保它固定在一個位置。

  2. 最后,我們修改 updateWorld() 方法的方式與你在處理檢測碰撞時學(xué)到的方法是一樣:

    function updateWorld() {
         world.Step(1 / 30, 10, 10);
         
         world.ClearForces(); // 清除作用力
         for (var b = world.GetBodyList(); b; b = b.GetNext()) {
             for (var c = b.GetContactList(); c; c = c.next) {
                 var contact = c.contact;
                 var fixtureA = contact.GetFixtureA();
                 var fixtureB = contact.GetFixtureB();
                 var bodyA = fixtureA.GetBody();
                 var bodyB = fixtureB.GetBody();
                 var userDataA = bodyA.GetUserData();
                 var userDataB = bodyB.GetUserData();
                 
                 if (userDataA == "barrier" || userDataB == "barrier") {
                     console.log(userDataA + "->" + userDataB);
                 }
             }
         }
    
         world.DrawDebugData(); // 顯示剛體debug輪廓
     }
    
  3. 我們遍歷所有的剛體,然后遍歷所有的接觸的剛體,當(dāng)我們發(fā)現(xiàn)與障礙物發(fā)生碰撞的剛體時,我們將在輸出窗口打印發(fā)生的相關(guān)信息

  4. 測試網(wǎng)頁,然后通過點(diǎn)擊使子彈運(yùn)動:

    源碼: article/ch07/ch07-3.html

    如你所見,子彈穿過障礙物,碰撞被檢測到,并在開發(fā)者工具控制臺輸出下面的文本:

    bullet->barrier
    

    上面的信息被輸出了兩次的情況,是因?yàn)楫?dāng)拋射物與障礙物發(fā)生碰撞時輸出一次,并且障礙物與拋射物發(fā)射碰撞時又輸出了一次。

注意:在 Javascript 版中,bullet->barrier 輸出了 14 次,猜測是循環(huán)中

小結(jié)

本章探討了兩個屬性的使用,你學(xué)習(xí)了在一個離散型模擬中怎樣管理連續(xù)碰撞檢測,以及怎樣創(chuàng)建被動剛體(感應(yīng)器),為了在檢測到碰撞時不要進(jìn)行決算。

太好了,你們在本書中的學(xué)習(xí)之旅也在此結(jié)束了,但是還有很多Box2D的知識。你也許可以通過本書的知識來制作 Box2D 游戲,但是程序的世界更新非常之快,你要一直更新自己的知識。

我建議你經(jīng)常去訪問 www.box2d.org 和 http://box2d.org/manual.pdf 官方網(wǎng)站和文檔,同樣我的博客 www.emanueleferonato.com 也會及時的更新最新的技巧和教程。

一旦你完成了你的第一個 Box2d 游戲,不要忘記感謝 Erin Catto(類庫的設(shè)計(jì)者)


本文相關(guān)代碼請?jiān)?/p>

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

注:轉(zhuǎn)載請注明出處博客園:王二狗Sheldon池中物 (willian12345@126.com)

總結(jié)

以上是生活随笔為你收集整理的2D物理引擎 Box2D for javascript Games 第七章 子弹和感应器的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。