资讯专栏INFORMATION COLUMN

JavaScript物理引擎之Matter.js与Box2d性能对比

whinc / 2442人阅读

摘要:数据采集因为是测试物理引擎的性能,这里不考虑,只采集物理引擎更新每一帧的时间,因为除开物理引擎,渲染引擎也会带来性能消耗。

前言

在挑选JavaScript 2D物理引擎的时候,不外乎两种主流的选择:第一种是老牌的Box2D,最开始的版本是C++实现的,后来有了很多种实现,比如flash版本和js版本,具体可看:https://stackoverflow.com/que...;第二种是新潮的matter-js,matter-js比较轻量,API和文档都比较有友好。

这段时间先后折腾了matter-js和Box2D,因为项目需要在微信小游戏端运行,对性能要求比较高,最终还是选择了Box2D。

但凡涉及到这种需要经常看源码才能使用的库中文社区都非常少干货,这段时间折腾之后打算整理一些文章,分享给社区也作为一个知识备忘。

本文简单对两个引擎的性能在不同平台上进行对比,其中Box2D采用的是TypeScript实现的版本:https://github.com/flyover/bo..., 作者仍然在更新,并且我看了下CocosCreator内置的物理引擎也是基于这个进行的封装,社区还是可以得到保证的。matter-js采用的是0.14.2版本(感觉作者已经更新不动这个库了:),大半年都不怎么活跃了)。

测试案例

在屏幕随机位置重复创建相同的矩形刚体,使之自由落体到底部,计算不同刚体数量下,全部刚体落地后每一帧的物理计算平均耗时。下面是测试中的一些截图:

影响性能的因素

机器本身的配置;

JIT:苹果端微信小游戏没有JIT,性能会大打折扣;

刚体的随机性:刚体在随机位置生成的过程中,如果与其他刚体重叠,物理引擎需要更多的性能消耗来修正重叠,因此,每次运行测试用例数据上都不可避免会有波动。

引擎本身的设计:比如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的。

关于圆形刚体

上面提到了两个引擎对于圆形刚体的设计,因为matter-js没有正统的圆形,我大胆猜测圆形刚体的性能Box2D会大大高于matter-js!

特意去翻了下各自的源码,首先我们来看看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,显然就是在越多边形碰撞检测需要的计算量越大!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/101192.html

相关文章

  • 游戏开发

    摘要:工欲善其事必先利其器游戏环境对比发表算法在游戏上超过人类之后,游戏研究迅速成为了研究热点。当然这不是网络游戏服务器架构概述一架构模型现代电子游戏,基本上都会使用一定的网络功能。 每个程序员都需要知道一些游戏网络知识 本文主要针对游戏的网络设计,在文章中目前主流的网络游戏实现方案都有讲解。从Peer-to-Peer 帧同步,客户端/服务器(c/s架构),客户端预测(Client-Side...

    Enlightenment 评论0 收藏0
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 4 - 游戏即将开始)

    摘要:经过这一节,万事俱备只欠东风,下一节我们就来完成这个游戏的剩余逻辑,比如接苹果加分,接到炸弹或苹果掉到地上游戏结束,还有加入更丰富的音效。 showImg(https://segmentfault.com/img/bVM22H?w=900&h=500); 回顾 上一节我们介绍了加载场景,并利用加载好的资源,丰富了开始界面。现在点击屏幕后仍是一片黑暗,那么,这一节我们就来完成游戏最核心的...

    Miyang 评论0 收藏0

发表评论

0条评论

whinc

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<