Matter.js 快速上手:创建第一个 2D 物理世界

作者:白露

时间:2026-11-03

浏览:323

本文系统讲解如何使用 Matter.js 从零搭建第一个 2D 物理世界,涵盖核心模块架构、画布初始化、刚体碰撞、物理属性调优及常见踩坑指南。

文章目录
在浏览器中模拟重力下落、物体反弹、摩擦滑动与碰撞反作用力,不需要从零手写牛顿运动定律。本文的核心目标是带领初学者以最精简的链路引入 Matter.js,实例化物理引擎与调试渲染器,生成可交互的刚体和静态边界,在 10 分钟内搭建一个完整运行的 Web 2D 物理世界。
Matter.js 快速上手:创建第一个 2D 物理世界
图 1:Matter.js 2D 物理世界的运行表现与核心构成

一、认识 Matter.js 的核心协作模块

Matter.js 是一个轻量级、开源且功能完备的 JavaScript 2D 刚体物理引擎。在开始写代码前,首先需要理清其模块设计。初学者常误以为“只要调用一个函数就能在屏幕上画出小球”,但实际上 Matter.js 将数学计算与视觉渲染严格拆分成了不同的角色。

Matter.js 快速上手:创建第一个 2D 物理世界
图 2:Matter.js 内部核心组件协作与信息传递逻辑

构建物理世界涉及的五个关键子模块如下:

  • Matter.Engine:物理引擎的心脏。负责维护时间流逝,并在每个时刻计算所有刚体的重力下坠、速度变化与碰撞反馈。
  • Matter.Render:内置的简易 Canvas 渲染器。它只负责“看”引擎里的数据并在画布上画出来。如果开发复杂大型游戏,可以用 PixiJS 或 Three.js 替换该模块。
  • Matter.Runner:循环协调器。利用浏览器的 requestAnimationFrame 确保物理世界的计算节奏与屏幕刷新率相一致。
  • Matter.Bodies:刚体工厂。提供快速生成矩形、圆形、梯形等基础几何刚体的方法。
  • Matter.Composite:物理对象容器。在 Matter.js 现代版本中,所有的物体、地面、弹簧约束都统一存放在 engine.world(一个根复合容器)中。

二、从零搭建物理世界的完整操作步骤

搭建第一个物理世界通常遵循固定的五个环节:引入库、解构命名空间、初始化引擎与画布、配置物理刚体,最后启动运行循环。

Matter.js 快速上手:创建第一个 2D 物理世界
图 3:搭建 Matter.js 2D 物理世界的标准五步流程

步骤 1:新建 HTML 并引入 Matter.js

创建一个基础的 index.html 文件,在页面中通过 CDN 脚本标签载入 Matter.js:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>My First Matter.js World</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      display: flex;
      justify-content: center;
      align-items: center;
      min-height: 100vh;
      background-color: #2c302e;
    }
  </style>
</head>
<body>
  <!-- 引入官方 CDN 构建包 -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.19.0/matter.min.js"></script>
  <script>
    // 后续 JS 代码将写在这里
  </script>
</body>
</html>

步骤 2:解构模块并初始化引擎与渲染器

在 <script> 中解构所需子模块,并创建 engine 与 render 实例:

// 1. 提取 Matter.js 常用类
const { Engine, Render, Runner, Bodies, Composite, Mouse, MouseConstraint } = Matter;

// 2. 创建物理计算引擎
const engine = Engine.create();

// 3. 创建画布渲染器
const render = Render.create({
  element: document.body, // 画布挂载的目标父容器
  engine: engine,         // 关联的物理引擎
  options: {
    width: 800,
    height: 600,
    wireframes: false,    // 设为 false 才能渲染实心填充色,否则仅显示线框
    background: '#FAF8F3' // 画布背景底色
  }
});

步骤 3:定义刚体(物体与静态边界)

注意:在 Matter.js 中,Bodies.rectangle(x, y, width, height) 传入的 x, y 是刚体的中心点坐标,而不是左上角坐标。

// 创建一个下落的方块:中心位于 (400, 100),宽 60,高 60
const box = Bodies.rectangle(400, 100, 60, 60, {
  render: {
    fillStyle: '#8A9478' // 自定义外观颜色
  }
});

// 创建一个下落的圆形小球:中心位于 (420, 40),半径 30
const ball = Bodies.circle(420, 40, 30, {
  restitution: 0.8,      // 弹性恢复系数:0.8 代表具有明显的反弹效果
  render: {
    fillStyle: '#D97A53'
  }
});

// 创建固定的静态地面:中心在 (400, 580),宽 800,高 40
// 必须设置 isStatic: true,否则地面也会受重力掉出屏幕!
const ground = Bodies.rectangle(400, 580, 800, 40, {
  isStatic: true,
  render: {
    fillStyle: '#464B48'
  }
});

// 创建一块左倾斜的静态滑梯挡板
const ramp = Bodies.rectangle(300, 350, 320, 20, {
  isStatic: true,
  angle: Math.PI * 0.12, // 倾斜约 21 度
  render: {
    fillStyle: '#464B48'
  }
});

步骤 4:装配物体并启动世界

使用 Composite.add 将上述刚体一次性放入物理世界,随后运行渲染器与主循环调度器:

// 将刚体批量注册到物理世界容器中
Composite.add(engine.world, [box, ball, ground, ramp]);

// 启动渲染管线
Render.run(render);

// 创建并运行主循环调度器
const runner = Runner.create();
Runner.run(runner, engine);

步骤 5:增加鼠标交互(可选但强烈推荐)

为了让物理世界生动可玩,可以通过 MouseConstraint 允许用户通过鼠标光标随意抓取刚体并拖拽抛掷:

// 绑定鼠标事件到渲染画布上
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
  mouse: mouse,
  constraint: {
    stiffness: 0.2, // 拖拽弹簧硬度
    render: {
      visible: false // 隐藏拖拽时连向鼠标的弹性辅助线
    }
  }
});

// 装载鼠标约束,并将事件同步给渲染器
Composite.add(engine.world, mouseConstraint);
render.mouse = mouse;
运行验证:保存并在浏览器中打开该 HTML,将看到一个带有底色的 800×600 画布。小球和方块在重力作用下从空中落下,砸在倾斜的滑梯上并发生滑移碰撞,最终反弹落在地面上。按住鼠标左键即可抓住小球或方块进行甩动。

三、刚体核心属性与力学行为解析

刚体的运动质感取决于其属性参数配置。下表梳理了调整物理手感时最常改动的四个属性:

Matter.js 快速上手:创建第一个 2D 物理世界
图 4:刚体类型判定与运动力学参数影响示意
属性名称 默认值 作用与影响 典型取值示例
isStatic false 是否为不动刚体。设为 true 时不可位移,充当地面或障碍物。 墙壁、柱子设为 true
restitution 0 恢复弹性系数(0 到 1)。数值越高,碰撞反弹保留的速度越多。 金属块 0.1,橡胶球 0.85
friction 0.1 表面滑动摩擦力。数值越大,与其它刚体接触时减速越剧烈。 冰面滑块 0.005,粗糙砂纸 0.8
density 0.001 刚体密度。Matter.js 会根据面积和密度自动推算刚体质量 mass。 木块 0.001,重铁球 0.05

四、初学者常见认知误区与规避建议

在实际编写代码时,初次接触物理引擎的开发者往往容易在以下几个概念上产生混淆:

误区 1:“Matter.Render 只能用来开发简易玩具,做不成完整产品”

修正辨析:这种说法有其事实依据,但推导并不严谨。Matter.Render 本身确实只是官方提供的一个调试用渲染器,它的重点是准确地描绘碰撞凸包、轴对齐包围盒与物理锚点,而非追求炫丽的粒子光效或贴图序列帧。

但这并不代表 Matter.js 不能用于生产。在商业游戏或互动应用中,业界通行的标准做法是完全废弃 Matter.Render,仅利用 Matter.Engine 纯在内存中计算每个物理刚体的 position.x、position.y 与 angle,然后将这些数值直接同步赋值给 Pixi.js 的精灵(Sprite)或 Three.js 的网格(Mesh)。架构解耦正是 Matter.js 最具生命力的特性之一。

误区 2:“添加物体要用 World.add(...)”

修正辨析:许多网上的旧版教程中遍布 World.add(engine.world, body) 的写法。虽然在较旧的 Matter.js 0.14~0.17 中它能正常运行,但在现代新版本中官方已将其标为废弃,统一推荐使用 Composite.add(engine.world, body)。World 本质上就是一个顶级的 Composite 容器,使用现代统一 API 可以避免未来大版本升级带来的废弃警告。

误区 3:“为什么给刚体设置了颜色,界面上仍然全是灰色空心线框?”

修正辨析:这是 90% 的初学者都会遭遇的陷阱。Matter.js 的 Render 默认配置项中,wireframes 属性缺省为 true。在该模式下,所有刚体都会以透明内部、灰色描边的方式绘制以方便观察碰撞边缘。如果希望自定的 fillStyle 生效,必须在 Render.create 的 options 中显式声明 wireframes: false。

五、总结与极简上手清单

创建 2D 物理世界并不是一项深奥的技术。只要掌握“模块解构 → 引擎与画布创建 → 刚体注入容器 → 启动主循环”这一主线逻辑,就能迅速搭建出生动有趣的力学模拟场景。

Matter.js 快速上手:创建第一个 2D 物理世界
图 5:Matter.js 极简上手避坑清单与进阶发展路线

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章