By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

什么物理引擎?

物理引擎是一个计算机程序,使用质量、速度、摩擦力和空气阻力等变量,模拟了一个近似真实的物理系统,为刚性物体赋予真实的物理效果,比如重力、旋转和碰撞等效果,让物体的行为表现的更加趋向真实。

百度百科,针对 物理引擎 解释

物理引擎通常有两种常见类型:实时物理引擎和高精度物理引擎。高精度物理引擎需要更多的处理能力来计算非常精确的物理,通常使用在科学研究(计算物理学)和动画电影制作。实时物理引擎常用于电子游戏并且简化了算法,降低精确度以减少处理时间,使得在游戏中有更好的处理速度。

物理引擎在游戏中的应用

在前端开发领域,物理引擎是比较小众的话题,通常作为游戏开发引擎附属工具出现。物理引擎仿真在计算机的虚拟世界中模拟物体在真实世界的表现(动力学仿真最为常见),让画面中物体的运动表现更符合玩家对现实世界的认知,比如在《愤怒的小鸟》游戏中被弹弓发射出去小鸟或是因为被撞击而坍塌的物体堆。

物理引擎可以帮助开发者更快速地实现诸如碰撞反弹、摩擦力、单摆、弹簧、布料等等不同类型的仿真效果。物理引擎通常并不需要处理和画面渲染相关的事务,而只需要完成计算仿真的部分就可以了。Matter.js 提供了基于 canvas2D API 的渲染引擎,可以结合 p2.js 与 CreateJS 或 Egret 渲染引擎使用。

游戏引擎和物理引擎的联合使用并没有想象中那么复杂,实际上只需要完成不同引擎之间的坐标系映射就可以了。

Matter.js 介绍

Matter.js 是一个用于 Web 的 JavaScript 2D 物理引擎库,该项目诞生于 2014 年 2 月 28 号(0.5.0-alpha 版本),它相较于老牌的 Box2D 引擎库,Matter.js 更为轻量级,并且在性能和功能方面也不逊色。

box2d.js 通过 Emscripten 将 c 语言转换为 asm.js 进行实现

Matter.js 特性

刚体 (Rigid bodies) 复合体 (Compound bodies) 组合体(Composite bodies)

Matter.js 基础概念

大多数的物理引擎对于物理模拟的要素都有着相近的概念,不同的引擎差别在于使用的方式,功能的全面性,模拟的精细度等层面,下面就先从物理世界的基础概念讲起。

Engine(引擎)和 World(世界)

Matter.Engine 模块包含了创建和处理引擎的方法,引擎是负责管理和更新模拟世界的控制器,引擎可以控制时间的缩放,可以检测所有的碰撞事件,并且拿到所有碰撞的物体对(pairs)。

在 Matter.js 中任何的物体都需要一个容身处,而存放这些物体的地方,我们称之为世界,物体必须添加到世界里,然后由引擎运行这个世界。而创建世界需要使用到 Matter.World 模块,该模块包含了用于创建和操作世界的方法,一个 Matter.World 相当于一个复合物体,物体、约束、复合物体的聚合体,其次世界还有额外的一些属性,比如重力、边界。

Render(渲染)

// Matter.Render 用法
const engine = Engine.create();
// 将物体加入到世界中
const render = Render.create({
    element: document.body,
    engine: engine,
    options: options
Engine.run(engine);
Render.run(render);
  • element 是一个容器元素,使用时指定要渲染的节点
  • engine 指定为 Matter.Engine 实例
  • options 指定一些渲染的参数
  • Matter.Render 是将实例渲染到 Canvas 中的渲染器,控制视图层的样式,它的主要作用是用于开发和调试,默认情况下 Matter.Render 将只显示物体的线框(轮廓),这对于开发和调试很有帮助,但如果需要使用到全局实体渲染则需要将线框模式关闭 render.options.wireframes = false,另外它同样也适合制作一些简单的游戏,因为它包括了一些绘图选项、线框、向量、Sprite 精灵和视窗功能。

    Body(刚体)

    物体或者叫刚体,在物理引擎里特指坚硬的物体,具有固定的形状,不能形变。刚体可以用于表示一个箱子、一个球或是一块木头,每个物体都有自己的物理属性,质量、速度、摩擦力、角度等,还可以设置刚体的标记。Matter.Bodies 模块中内置了几种刚体,矩形 Matter.rectangle、多边形 Matter.polygon、圆形 Matter.circle 、梯形 Matter.trapezoid 等等。

    // 创建刚体
    const rect = Bodies.rectangle(200, 100, 50, 50), // 矩形
        circle = Bodies.circle(300, 100, 25), // 圆
        polygon = Bodies.polygon(450, 100, 5, 25), // 多边形
        trapezoid = Bodies.trapezoid(590, 100, 50, 50, 3); // 梯形
    // 将刚体添加到世界中
    World.add(engine.world, [rect, circle, polygon, trapezoid]);
    

    Composite(复合体)

    由刚体和复合材料通过约束组合在一起的就叫做复合体。复合体对外当作一个刚体,复合体的物理属性是通过所包含的刚体的属性综合计算出来的。Matter.Composite 模块包含用于创建和处理复合体的方法,另外还有一个 Matter.Composites 模块,提供了几种特别的复合材料,例如 链 Composites.chain、牛顿摆球 Composites.newtonsCradle、软体 Composites.softBody、汽车 Composites.car 、堆叠 Composites.stack 等等。

    桥梁 (Bridge)

    // 使用堆叠创建桥梁
    const group = Body.nextGroup(true);
    const bridge = Composites.stack(150, 300, 9, 1, 10, 10, function(x, y) {
        return Bodies.rectangle(x, y, 50, 20, {
            collisionFilter: { // 过滤碰撞
                group: group
    // 创建链约束
    Composites.chain(bridge, 0.5, 0, -0.5, 0, { stiffness: 0.9 });
    

    布 (Cloth)

    // 软体
    const cloth = Composites.softBody(200, 200, 20, 12, 5, 5, false, 8, {
        friction: 0.00001, // 摩擦力
        collisionFilter: {
            group: Body.nextGroup(true)
        render: {
            visible: false
    

    牛顿摆球 (Newton's Cradle)

    // 创建牛顿摆球
    const newtonsCradle = Composites.newtonsCradle(300, 320, 5, 25, 150);
    

    Constraint(约束)

    约束可理解为通过一条线,将刚体 A 和刚体 B 两个刚体连接起来,被约束的两个刚体由于被连接在了一起,移动就相互受到了限制。Matter.Constraint 模块包含了用于创建和处理约束的方法,这个约束可以很宽松,也可以很紧绷,还可以定义约束的距离,约束具有弹性,可以用来当作橡皮筋。

    // 创建一个矩形和圆形
    const rect = Bodies.rectangle(400, 100, 50, 50, {
          isStatic: true
        ball = Bodies.circle(400, 400, 50);
    World.add(engine.world, [
        rect,
        ball,
        Constraint.create({
            bodyA: rect, // 约束刚体 A
            pointA : { // 约束点 A
                x: 0,
            bodyB: ball, // 约束刚体 B
            pointB: { // 约束点 B
                x: 0,
                y: -50
            stiffness: 0.6
    

    MouseConstraint(鼠标约束)

    如果你想让刚体与用户之间有交互,那就要在鼠标和刚体之间建立连接,也就是鼠标和刚体间的约束,Matter.MouseConstraint 模块包含用于创建鼠标约束的方法,提供通过鼠标或触摸(移动端时)移动刚体的能力,可以设置什么标记的物体才能被鼠标操纵,创建鼠标约束后,可以捕获到鼠标的各类事件。

    // 全局鼠标约束
    const mouseConstraint = MouseConstraint.create({
      element: render.canvas
    World.add(engine.world, mouseConstraint);
    
    // 设置某个标记的物体才能被鼠标操纵
    const categoryBall = 0x0001; // 分类
    const ball = Matter.Bodies.circle(300, 350, 32, {
      density: 0.68, // 密度
      restitution: 1, // 弹性
      collisionFilter: {
        category: categoryBall
    const mouseConstraint = MouseConstraint.create({
      element: render.canvas,
      collisionFilter: {
      	mask: categoryBall
    World.add(engine.world, mouseConstraint);
    

    Vector(向量)

    Matter.Vector 模块包含用于创建和操纵向量的方法,向量是引擎有关几何操作行为的基础,修改物体的运动状态基本都是使用向量来控制,例如赋予物体一个力,或者设置物体的速度、旋转角度,并且内置了多个向量的求解函数:向量积、标量积、格式化、垂直向量等等。

    Events(事件)

    Matter.Events 模块包含了绑定、移除和触发对象的方法。

  • 绑定事件 Matter.Events.on(object, eventNames, callback)
  • 移除事件 Matter.Events.off(object, eventNames, callback)
  • 触发事件 Matter.Events.trigger(object, eventNames, event)
  • Matter.js 中的一些属性

    Matter.Body.applyForce(body, position, force) 方法可以给刚体施加一个力,传入 X 和 Y 轴需要的力度值,通过这个方法你可以去模拟踢一个足球、投一个篮球的效果。

    const ball = Bodies.circle(300, 100, 25, {
      density: 0.68, // 密度
      restitution: 0.8 // 弹性
    World.add(engine.world, ball);
    function addForce() {
      let forceMagnitude = 0.02 * ball.mass;
      Body.applyForce(ball, ball.position, {
      	x : (forceMagnitude + Common.random() * forceMagnitude) * Common.choose([1, -1]),
      	y : -forceMagnitude + Common.random() * -forceMagnitude
    addForce();
    

    可以设置 X、Y 轴的重力值,默认都为 1,参数在 0、1、-1 中选择使用。

    // 实现反重力效果
    engine.world.gravity.y = -1;
    // 无重力效果
    engine.world.gravity.y = 0;
    

    通过 enableSleeping: true 开启睡眠模式后,当刚体处于不受作用状态时,会进入睡眠状态,这样可以有效的提高引擎的性能,当物体被其他物体碰撞或者对刚体施加力时,刚体会被叫醒,引擎会继续对其进行计算模拟。

    // 开启睡眠状态
    const engine = Engine.create({
    	enableSleeping: true
    // 还可以针对进入睡眠状态的刚体进行监听,比如将刚体移出世界
    Event.on(ball, "sleepStart", function() {
    	World.remove(engine.world, ball);
    

    摩擦力在 Matter.js 中分别提供了三种:摩擦力 friction、空气摩擦力 frictionAir 以及静止摩擦力 frictionStaticfriction 默认值是 0.1,取值范围在 0 - 1,当值为 0 意味着刚体可以摩擦力的无限滑动,1 意味着对刚体施加力后会立刻停止,frictionAir 默认值是 0.01,取值范围 0 - 1,当值为 0 意味着刚体在空间中移动时速度永远不会减慢,值越高时刚体在空间的移动速度越慢,frictionStatic 默认值 0.5,当值为 0 时意味着刚体几乎是静止的,值越高时意味着需要移动刚体所需的力就越大。

    // 摩擦力
    Bodies.rectangle(300, 70, 40, 40, {
    	friction: 0.01
    // 空气摩擦力
    Bodies.rectangle(300, 70, 40, 40, {
    	frictionAir: 0.05
    // 静止摩擦力
    Bodies.rectangle(300, 70, 40, 40, {
    	frictionStatic: 1
    

    可以控制全局的时间,当值为 0 时为冻结模拟,值为 0.1 给出慢动作效果,值为 1.2 时给出加速效果。

    engine.timing.timeScale = 0.1;
    

    这里就简单提及到几个属性,当然还有更多的属性比如:视图(View)、弹性(Restitution)等等,更详细的 API 可到官网查看。

    Matter.js 调试

    除了前面讲 Matter.Render 模块的时候提到的线框模式 wireframes 便于调试外,Matter.Render 模块其实还为我们提供了以下几种方法,便于我们自定义调试选项:

    const render = Render.create({
        element: document.body,
        engine: engine,
        options: {
            width: 800,
            height: 600,
            pixelRatio: 1, // 设置像素比
            background: '#fafafa', // 全局渲染模式时背景色
            wireframeBackground: '#222', // 线框模式时背景色
            hasBounds: false,
            enabled: true,
            wireframes: true, // 线框模式
            showSleeping: true, // 刚体睡眠状态
            showDebug: false, // Debug 信息
            showBroadphase: false, // 粗测阶段
            showBounds: false, // 刚体的界限
            showVelocity: false, // 移动刚体时速度
            showCollisions: false, // 刚体碰撞点
            showSeparations: false, // 刚体分离
            showAxes: false, // 刚体轴线
            showPositions: false, // 刚体位置
            showAngleIndicator: false, // 刚体转角指示
            showIds: false, // 显示每个刚体的 ID
            showVertexNumbers: false, // 刚体顶点数
            showConvexHulls: false, // 刚体凸包点
            showInternalEdges: false, // 刚体内部边界
            showMousePosition: false // 鼠标约束线
    

    另外官方提供了三个调试工具,可单独使用或一起使用,如下:

    工具 matter-tools

  • MatterTools.Demo 用于运行和测试 DEMO
  • MatterTools.Gui 改变引擎的属性
  • MatterTools.Inspector 检查世界
  • Other Resource

    使用Phaser3+Matter.js实现“合成大西瓜”游戏

    PolyK 用 Javascript 编写的多边形库

    Slicing, splitting and cutting HTML5 physics bodies using Phaser, Matter.js and PolyK

    H5游戏开发:决胜三分球

    H5游戏开发:套圈圈

    cannon.js - A lightweight and simple 3D physics engine for the web

    pixijs