在挑选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
在屏幕随机位置重复建立相同的矩形刚体,使之自由落体到底部,计算不一样刚体数量下,所有刚体落地后每一帧的物理计算平均耗时。下面是测试中的一些截图:数组
由于是测试物理引擎的性能,这里不考虑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');
机型 | 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 |
机型 | 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,显然就是在越多边形碰撞检测须要的计算量越大!