JavaScript物理引擎之Matter.js與Box2d性能對比

前言

在挑選JavaScript 2D物理引擎的時候,不外乎兩種主流的選擇:第一種是老牌的Box2D,最開始的版本是C++實現的,後來有了不少種實現,好比flash版本和js版本,具體可看:https://stackoverflow.com/que...;第二種是新潮的matter-js,matter-js比較輕量,API和文檔都比較有友好。javascript

這段時間前後折騰了matter-js和Box2D,由於項目須要在微信小遊戲端運行,對性能要求比較高,最終仍是選擇了Box2D。java

但凡涉及到這種須要常常看源碼才能使用的庫中文社區都很是少乾貨,這段時間折騰以後打算整理一些文章,分享給社區也做爲一個知識備忘。git

本文簡單對兩個引擎的性能在不一樣平臺上進行對比,其中Box2D採用的是TypeScript實現的版本:https://github.com/flyover/bo..., 做者仍然在更新,而且我看了下CocosCreator內置的物理引擎也是基於這個進行的封裝,社區仍是能夠獲得保證的。matter-js採用的是0.14.2版本(感受做者已經更新不動這個庫了:),大半年都不怎麼活躍了)。github

測試案例

在屏幕隨機位置重複建立相同的矩形剛體,使之自由落體到底部,計算不一樣剛體數量下,所有剛體落地後每一幀的物理計算平均耗時。下面是測試中的一些截圖:
圖片描述圖片描述數組

影響性能的因素

  1. 機器自己的配置;
  2. JIT:蘋果端微信小遊戲沒有JIT,性能會大打折扣;
  3. 剛體的隨機性:剛體在隨機位置生成的過程當中,若是與其餘剛體重疊,物理引擎須要更多的性能消耗來修正重疊,所以,每次運行測試用例數據上都不可避免會有波動。
  4. 引擎自己的設計:好比matter-js沒有圓形的定義,建立圓形剛體本質上是建立25邊形,而Box2d自然就設計了圓形剛體,因此對於圓形剛體,兩個引擎會存在不小的差別。

數據採集

由於是測試物理引擎的性能,這裏不考慮FPS,只採集物理引擎更新每一幀的時間,由於除開物理引擎,渲染引擎(PixiJS)也會帶來性能消耗。微信

// Box2d數據打點
let positionIterations = 3;
let velocityIterations = 8;
let timeStep           = 1 / 60;
Performance.startPoint('box2dUpdateCost');
world.Step(timeStep, velocityIterations, positionIterations);
Performance.endPoint('box2dUpdateCost');
// matter-js數據打點
Performance.startPoint('matterUpdateCost');
matter.Engine.update(this.engine, 1e3 / this.fps);
Performance.endPoint('matterUpdateCost');
// 計算平均耗時
function calAverage(list, key) {
    let sum = list.reduce((total, curr) => curr[key] + total, 0);
    console.log(sum / list.length)
}

// 全部數據會收集到一個數組裏面
let data = Performance.print();

//calAverage(data, 'matterUpdateCost');
calAverage(data, 'box2dUpdateCost');

Box2D數據

機型 10個剛體 20個剛體 50個剛體 100個剛體 200個剛體 300個剛體
MacBook Pro 2015 0.2ms 0.4ms~0.5ms 0.6ms~0.8ms 1.3ms~1.6ms 4.6ms~5.6ms 7ms~8ms
iPhone7 Plus微信小遊戲 3.3ms~3.5ms 4.5ms~5.5ms 7.5ms~8.5ms 13ms~14ms 33ms 60ms+
OPPO R11 Plus微信小遊戲 1.5ms~2.5ms 1.8ms~3ms 3.6ms 6ms~8ms 9ms~12ms 17ms~19ms

matter-js數據

機型 10個剛體 20個剛體 50個剛體 100個剛體 200個剛體 300個剛體
MacBook Pro 2015 0.5ms~0.6ms 0.6ms~1ms 2ms~3ms 3.5ms~4ms 6ms~8ms 12ms~13ms
iPhone7 Plus微信小遊戲 2.3ms~2.8ms 3.0ms~3.5ms 6.0ms~6.5ms 11.5ms~12ms 26ms~28ms 45ms
OPPO R11 Plus微信小遊戲 1.5ms~2.5ms 2.5ms 5~6ms 8ms 12ms~14ms 30ms

結論

在PC端,Box2d全面打敗了matter-js,在蘋果的微信小遊戲端,由於沒有JIT,Box2d性能反而不如matter-js,而回到安卓的微信小遊戲端,由於有JIT,Box2d一樣是能夠打敗matter-js的。app

關於圓形剛體

上面提到了兩個引擎對於圓形剛體的設計,由於matter-js沒有正統的圓形,我大膽猜想圓形剛體的性能Box2D會大大高於matter-js!ide

特地去翻了下各自的源碼,首先咱們來看看matter-js的:性能

Bodies.circle = function(x, y, radius, options, maxSides) {
    options = options || {};
    var circle = {
        label: 'Circle Body',
        circleRadius: radius
    };
                                
     // approximate circles with polygons until true circles implemented in SAT
    maxSides = maxSides || 25;
    var sides = Math.ceil(Math.max(10, Math.min(maxSides, radius)));

    // optimisation: always use even number of sides (half the number of unique axes)
    if (sides % 2 === 1)
        sides += 1;
        
    return Bodies.polygon(x, y, sides, radius, Common.extend({}, circle, options));
};

從上面的代碼可得,matter-js將25邊形當成圓,這裏在進行碰撞檢測的時候,會比純圓有更多的計算量,不知道matter-js做者是出於什麼目的這樣設計。測試

再來看看Box2D版本的實現:

class b2CircleShape extends b2Shape {
      constructor(radius = 0) {
          super(exports.b2ShapeType.e_circleShape, radius);
          this.m_p = new b2Vec2();
      }
      Set(position, radius = this.m_radius) {
          this.m_p.Copy(position);
          this.m_radius = radius;
          return this;
      }
}

與matter-js相比,Box2D的圓與多邊形是獨立的。

多說無益,咱們對比下100個剛體狀態下,兩個引擎的數據對比,爲了凸顯差距,咱們選擇Box2D打不過matter-js的蘋果端微信小遊戲平臺查看數據:

引擎 耗時
Box2D 8ms
matter-js 25ms

咱們能夠得出一個有意思的結論:一樣是100個剛體,矩形剛體的耗時是13ms~14ms,而圓形剛體的耗時降低到了8ms,這對於一些彈球類的遊戲無疑是福音,據個人觀察,100個圓形剛體在蘋果端微信小遊戲下面絲絕不會卡頓。而matter-js的耗時從11.5ms~12ms上升到了25ms,顯然就是在越多邊形碰撞檢測須要的計算量越大!

相關文章
相關標籤/搜索