本文简介
戴尬猴,我是德育处主任
欢迎来到《物理世界的互动之旅:Matter.js入门指南》。
本文将带您探索 Matter.js
,一个强大而易于使用的 JavaScript
物理引擎库。
我将介绍 Matter.js
的基本概念,包括引擎、世界、物体和约束等。
本文还提供丰富的代码示例,帮助各位工友更好地理解如何使用 Matter.js
创建令人惊叹的物理场景(先画个饼吧~)。
本文是我的学习笔记和个人理解,在翻译和部分概念的理解上可能存在一点偏差,如果发现本文有什么错漏的地方,请自行调节呼吸频率。我懒得改~
本文前1000字都在讲一些基础概念,你觉得无聊可以先看后面的内容,看完再回来过一遍基础概念就行了。
Matter.js是什么?
在现实世界中,物理是无处不在的。从行星和恒星的运动到电子的运动,物理定律描述了我们周围几乎所有事物的运动和相互作用。
在计算机科学中,物理引擎是一种模拟物理现象的软件程序。它们通常用于创建物理游戏、虚拟现实和仿真等应用程序。物理引擎可以模拟各种现象,例如重力、碰撞和摩擦等。物理引擎通常是非常复杂的,因为它必须模拟现实世界中的各种效果。
在Web浏览器想模拟真实世界的物理现象其实也有很多库,2D方面有 Matter.js
、P2.js
等,3D方面有 Cannon.js
、ammo.js
等。
而本文是将 Matter.js
的,所以我在这只会说 Matter.js
的好话。
Matter.js
是一个非常强大的 JavaScript
2D物理引擎,它能够帮助你在Web应用程序中实现逼真的物理效果。
Matter.js
提供了可定制的碰撞检测、重力、力学效应和运动控制等功能,让你可以快速、简单地构建交互式的物理模拟。无论是模拟游戏、建筑模型还是实验室实验,Matter.js
都可以满足你的需求。
Matter.js官网 ⚡️
基础概念
在学习 Matter.js
前,我们需要了解一些基础概念。由于本文是入门篇,所以我只介绍常用的基础概念。
模块名称 | 说明 |
---|---|
引擎(Engine) | 引擎 Engine 是 Matter.js 的核心组件,用于管理物理世界中的所有对象、计算物体的运动和相互作用。用来模拟真实环境的。 |
渲染器(Render) | 渲染器 Render 用于将物理世界中的对象可视化。意思就是它能将物体渲染到屏幕上。 |
复合体(Composite) | 是包含多个刚体和约束的容器,它们可以作为单个物理对象进行操作。 |
刚体(Body) | 表示具有物理属性的实体,如形状、质量和速度等。刚体可以是各种形状,例如矩形、圆形、多边形等。 |
约束(Constraint) | 用于约束刚体的相对运动,例如让两个刚体之间的距离保持不变、限制旋转等。 |
循环模块 (Runner) |
Runner 用于管理和控制物理引擎的主循环。 |
我用自己的话粗略总结一下(但我感觉我总结得不太正确,工友们有更好的理解可以到评论区留句话,没什么好说的也可以写句“到此一游”)。
引擎 Engine
可以模拟我们真实世界的一些物理法则。
刚体 Body
可以粗略理解为现实世界中的物体,比如一个球、一张凳子。
复合体 Composite
是一个容器,可以将多个物体整合起来,让它们产生联系。比如创建了一个球(刚体),然后用 Composite
将球和引擎连接起来,这样球就会收到物理规则的影响了。
渲染器 Render
就是个眼睛的作用,它能帮助我们看到 Matter.js
创建出来的世界。
约束 Constraint
就是约束,比如一个跷跷板由一根很长的模板和一个底座组成,底座固定在地面,木板的中间锁定在底座上面,这个锁定动作就是约束。正因为有这个约束,所以跷跷板才能成为跷跷板。
循环模块 Runner
可以粗略的理解为现实世界中的时间。如果没有循环模块,页面的所有元素都是定格的。你可以理解为现实世界没有时间的话,整个世界都会静止。
以上就是我觉得 Matter.js
入门阶段需要了解的一些基础概念。
除此之外其实还需要掌握一些基础物理概念,比如知道什么是碰撞,什么事摩擦力、阻力、重力等。这类概念会在接下来的案例中讲解。
安装Matter.js
在开始使用 Matter.js
之前,需要确保在项目中安装了它。
可以通过 npm
在命令行中安装,也可以通过 cdn
的方式引入。
CDN
在 github
上下载并引入到你的项目即可 github地址️⚡️。
你也可以 在这找到指定版本⚡️。
如果你不想把 Matter.js
下载到本地,也可以在 bootcdn 搜索 Matter.js
并引入。
<script src="https://cdn.bootcdn.net/ajax/libs/matter-js/0.19.0/matter.js"></script>
NPM
Matter.js 的 npm 地址⚡️
npm install matter-js
起步,第一个 Matter.js 应用
这个例子是 Matter.js 官方的起步案例
,通过这个例子你可以快速理解到前面讲的 Matter.js
基础概念。
先看效果。
从这个动图我们可以看出:
- 这个世界有2个正方形和一个地面(底部的长方形)。
- 正方形出现在空中,然后做自由落体运动。
- 左边的正方形碰到地面后出现了一点回弹。
- 右边的正方形落地前砸到左边的正方形,阻止了左边正方形的回弹,并且自己往右滚动了一下。
要使用 Matter.js
实现上面的效果,需要做以下几步:
- 创建容器。
- 引入
Matter.js
。 - 创建引擎。
- 创建渲染器,绑定画布上。
- 创建正方形和地面,并且让地面元素保持静止。
- 将创建好的元素添加到“世界”里(没错,你就是创世神~)。
- 最后,为这个世界添加“时间”属性,让它可以运转起来(
Matter.Runner
)。
上面所说的步骤还需要对应基础概念的表格配合理解。
转换成代码
<!-- 1. 创建容器 -->
<div id="c"></div>
<!-- 2. 引入 matter -->
<script src="../js/matter.js"></script>
<script>
const Engine = Matter.Engine
const Render = Matter.Render
const Bodies = Matter.Bodies
const Composite = Matter.Composite
const Runner = Matter.Runner
// 3. 创建引擎
let engine = Engine.create()
// 4. 创建渲染器,并将引擎连接到画布上
let render = Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
})
// 5-1. 创建两个正方形
let boxA = Bodies.rectangle(400, 200, 80, 80)
let boxB = Bodies.rectangle(450, 50, 80, 80)
// 5-2. 创建地面,将isStatic设为true,表示物体静止
let ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true })
// 6. 将所有物体添加到世界中
Composite.add(engine.world, [boxA, boxB, ground])
// 7. 执行渲染操作
Render.run(render)
// 8. 创建运行方法
var runner = Runner.create()
// 9. 运行渲染器
Runner.run(runner, engine)
</script>
我们使用 Engine
创建引擎,Matter.js
的这个引擎默认帮我们定义好这个世界的基本运行规律。
然后我们使用 Render
创建渲染器,这个渲染器可以将引擎和页面绑定在一起。
Bodies
是刚体的意思,用它来创建物体的,本例就创建了2个正方形和1个地面。
Composite
就是前面讲到的复合体,它可以让世界和物体产生关联,也就是说可以将物体添加到世界中。
最后通过 Render
让这个世界有了“时间”的概念,物体也会根据世界的规则在时间的运行下产生运动。
上面的代码也许你还不理解每个方法的具体使用方式,但结合我前面的分析,我相信你已经大概了解 Matter.js
“创造世界”的基本流程(也许听完我的解析后更懵了)。
渲染器
在前面的例子中,我们使用 Matter.Render.create
将画布和页面元素绑定在一起。此时默认的画布尺寸是 800px * 600px
。
// 省略部分代码
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
})
其实它还支持其他属性配置,可以设置画布宽高等信息。
设置画布宽高
使用 Matter.Render.create
时还能传入 options
参数。
// 省略部分代码
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400
}
})
关闭线框模式
Matter.js
创建的形状默认是线框模式的,你可以手动关闭这个模式,Matter.js
就会自动帮你填充一些颜色到基础图形上。
关闭线框模式的方式是将 wireframes
设置为 false
。
// 省略部分代码
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
wireframes: false
}
})
其他代码,包括创建图形的代码都和“起步,第一个 Matter.js 应用”一样。
options
还支持其他的配置,有兴趣的工友可以看看 文档⚡️。
图形元素
Matter.js
支持多种基础图形,包括矩形、圆形、三角形、梯形、多边形等。这些图形还支持配置颜色、摩擦力等属性。
基础图形
先说说基础。
在 Matter.js
文档中你会留意到创建物体使用的是 Body
或者 Bodies
,翻译成中文就是“刚体”。
在物理世界中,刚体是指在运动中和受力作用后,形状和大小不变,而且内部各点的相对位置不变的物体。
在 Matter.js
中,刚体(Body
) 是一种物理对象,它具有质量、位置、速度、加速度和形状等属性,可以被添加到物理世界中并受到物理引擎的模拟。例如矩形和圆形。
在入门阶段,我们可以使用 Bodies
创建基础图形。
矩形 rectangle
前面我们已经使用过矩形了。在这小节粗略讲解一下创建矩形的一些必传参数。
创建矩形使用的是 Matter.Bodies.rectangle(x, y, width, height)
方法。
参数 x
和 y
是矩形中心点的坐标,width
和 height
是矩形的宽高。
如果创建一个 80*80 的矩形,希望它的左上角在 (0, 0) 的位置,那 x
和 y
分别设置成 width
和 height
的一半。
// 省略部分代码
// 创建矩形
let rect = Matter.Bodies.rectangle(40, 40, 80, 80)
// 将矩形添加到世界里
Matter.Composite.add(engine.world, rect)
圆形 circle
创建圆形的方法是 Matter.Bodies.circle(x, y, radius)
。
x
和 y
是圆心坐标, radius
是半径。
// 省略部分代码
// 创建圆形
let circle = Matter.Bodies.circle(40, 40, 40)
// 将矩形添加到世界里
Matter.Composite.add(engine.world, circle)
梯形 trapezoid
创建梯形的方法是 Matter.Bodies.trapezoid(x, y, width, height, slope)
。
x
和 y
定义了梯形的中心点坐标,width
和 height
是梯形的宽高,slope
是斜率。
- 当斜率
slope
大于0小于1时,梯形的上边小于下边。 - 当斜率
slope
等于0时,梯形的上边和下边相等,看起来就是一个矩形。 - 当斜率
slope
小于0时,上边大于下边。 - 当斜率
slope
大于等于1时,就会呈现出三角形的样子。
// 省略部分代码
let trapezoid = Matter.Bodies.trapezoid(200, 200, 80, 80, 0.5)
三角形 trapezoid
创建三角形的方法和梯形一样,只需将斜率 slope
设置成大于等于1的值即可。
// 省略部分代码
let triangle = Matter.Bodies.trapezoid(200, 200, 80, 80, 1)
// 省略部分代码
let triangle = Matter.Bodies.trapezoid(200, 200, 80, 80, 2)
正多边形 polygon
Matter.js
使用 Matter.Bodies.polygon(x, y, sides, radius)
创建正多边形。
注意,是正多边形!
参数 x
和 y
是多边形中心点的坐标,sides
可以设置多边形的边的数量,radius
设置多边形的半径。
// 省略部分代码
let polygon = Matter.Bodies.polygon(200, 200, 7, 40)
自定义多边形
使用Matter.js创建自定义多边形,可以使用 Matter.Bodies.fromVertices(x, y, vertexSets)
方法。
x
和 y
定义多变西女中心的坐标,vertexSets
定义多边形顶点集合。
// 省略部分代码
// 定义顶点
const vertices = [
{ x: 0, y: 0 },
{ x: 50, y: 0 },
{ x: 50, y: 50 },
{ x: 25, y: 75 },
{ x: 0, y: 50 }
]
// 自定义多边形
const trapezoid = Matter.Bodies.fromVertices(100, 100, vertices)
// 将自定义多边形添加到世界里
Matter.Composite.add(engine.world, trapezoid)
图形状态和属性配置
前面使用 Matter.bodies
创建的图形时,可以在最后加多一个对象参数,这个参数可以配置图形的状态和属性。
填充色 render.fillStyle
如果您想为Matter.js中的形状添加填充色,可以在 render 属性中配置 fillStyle
属性的值。例如,要将圆形的填充色设置为橙色,可以使用以下代码:
// 省略部分代码
// 创建渲染器
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400,
wireframes: false, // 关闭线框模式
}
})
// 省略部分代码
// 创建矩形
let rect = Matter.Bodies.rectangle(200, 200, 80, 80, {
render: {
fillStyle: 'orange'
}
})
需要注意的是,使用填充色功能时,要关掉渲染器的线框模式。
边框颜色和线宽 render.strokeStyle & render.lineWidth
使用 render.strokeStyle
可以设置边框颜色,使用 render.lineWidth
可以设置边框的宽度。
// 省略部分代码
// 创建渲染器
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400,
wireframes: false, // 关闭线框模式
}
})
// 省略部分代码
// 创建矩形
let rect = Matter.Bodies.rectangle(200, 200, 80, 80, {
render: {
strokeStyle: '#3490de', // 设置边框颜色
lineWidth: 20 // 设置边框宽度
}
})
render.fillStyle
和 render.strokeStyle
都支持 颜色关键字、#开头的十六进制、rgb、rgba等 颜色值。
但不支持 0x
开头的十六进制颜色。
贴图 render.sprite
一个优秀的前端必须懂得贴图,Matter.js
也提供了贴图功能。
只需要配置一下 render.sprite
即可。
我用矩形举例。
// 省略部分代码
// 创建矩形
let rect = Matter.Bodies.rectangle(200, 200, 200, 200, {
render: {
sprite: { // 使用精灵
texture: './monkey.jpg' // 图片纹理位置
}
}
})
// 将所有物体添加到世界中
Matter.Composite.add(engine.world, rect)
缩放贴图 scale
如果需要设置贴图的宽高,还可以修改 xScale
和 yScale
属性。
但这两个属性只会影响贴图的尺寸,图形的真实尺寸并不会受到影响。
// 省略部分代码
let rect = Matter.Bodies.rectangle(200, 200, 200, 200, {
render: {
sprite: {
texture: './monkey.jpg',
xScale: 0.5,
yScale: 1.5
}
}
})
贴图偏移 offset
可以设置精灵图的 xOffset
和 yOffset
。
// 省略部分代码
let rect = Matter.Bodies.rectangle(200, 200, 200, 200, {
render: {
sprite: {
texture: './monkey.jpg',
xOffset: 0.5,
yOffset: 1
}
}
})
不透明度 render.opacity
opacity
的取值范围是 0 ~ 1
。
// 省略部分代码
let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {
render: {
opacity: 0.5
}
})
元素可见性 render.visible
当 render.visible
为 false
时,元素会隐藏;反之元素就显示。render.visible
的默认值是 true
。
// 省略部分代码
let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {
render: {
visible: false // 隐藏元素
}
})
旋转 angle
angle
属性可以设置元素的旋转弧度。
为了方便理解,我还是更习惯用“角度”这个单位。
弧度转角度可以用这个公式:
Math.PI / 180 * 角度
// 省略部分代码
// 矩形
let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {
angle: Math.PI / 180 * 45
})
上面这段代码创建了一个矩形,并且让他旋转45度。结合上面的公式应该比较容易理解。
空气阻力 frictionAir
前面简单的介绍了一下基础图形怎么填充颜色、怎么使用贴图,这些都前菜。
Matter.js
真正的亮点是物理引擎。
在前面有讲到,要让物理引擎动起来,需要用到下面这段代码
// 省略部分代码
// 创建运行方法
let runner = Runner.create()
// 运行渲染器
Runner.run(runner, engine)
如果忘了,可以看看前面的 “起步,第一个 Matter.js 应用” 这章节。
先介绍一下空气阻力。
我们知道,在地球上,当一个物体做自由落体运动时,会受到空气阻力的影响。
Matter.js
提供了 frictionAir
这个属性可以让我们给指定物体配置具体的空气阻力。
// 省略部分代码
let rectA = Matter.Bodies.rectangle(80, 100, 80, 80, {
frictionAir: 0.1 // 设置空气阻力
})
let rectB = Matter.Bodies.rectangle(200, 100, 80, 80, {
frictionAir: 0.5 // 设置空气阻力
})
let rectC = Matter.Bodies.rectangle(320, 100, 80, 80, {
frictionAir: 1 // 设置空气阻力
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 6. 将所有物体添加到世界中
Matter.Composite.add(engine.world, [rectA, rectB, rectC, ground])
从左往右的立方体中,我分别给它们配置的空气阻力时 0.1
、0.5
和 1
,数值越大,空气阻力就越大,自由落体的速度也就越慢。
回弹力 restitution
前面的例子中创建的物体都是没有弹力的,它们掉到地面时不会回弹。
如果希望物体有弹性,可以配置它的 restitution
。
// 省略部分代码
let rectA = Matter.Bodies.rectangle(80, 100, 80, 80, {
restitution: 0 // 设置弹力
})
let rectB = Matter.Bodies.rectangle(200, 100, 80, 80, {
restitution: 1 // 设置弹力
})
let rectC = Matter.Bodies.rectangle(320, 100, 80, 80, {
restitution: 1.2 // 设置弹力
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 6. 将所有物体添加到世界中
Matter.Composite.add(engine.world, [rectA, rectB, rectC, ground])
在 Matter.js
中,物体的回弹力正常取值范围是 0 ~ 1
。其中0表示碰撞后不反弹,1表示碰撞后完全反弹。
如果反弹系数大于1,就意味着碰撞后物体的能量增加,这是不符合物理规律的。
但如果你在做游戏,在处理游戏角色的某些技能时也可以让回弹力超出1。毕竟这是你的世界。
质量 mass
在初中物理课上我们知道,质量越大,惯性越大。也就是说物体更难改变它的状态(静止或运动状态)。当施加力或者撞击物体时,质量越大的物体会更难加速或者减速,需要更长的时间来达到相同的速度或者停止。而质量越小的物体则更容易改变它的状态,可以更快地加速或减速。
在 Matter.js
中,碰撞响应的计算是基于物体的质量和速度等参数的。比如,当两个物体相撞时,质量越大的物体会对速度的改变产生更小的影响,而质量越小的物体会对速度的改变产生更大的影响。
举个例子,我在画布中创建3个质量不同的矩形,左边的矩形的质量最小,右边的最大。在回弹力相同的情况下,质量越小,回弹的程度就越大。
// 省略部分代码
// 矩形A
let rectA = Matter.Bodies.rectangle(80, 100, 80, 80, {
restitution: 1,
mass: 0.1
})
// 矩形B
let rectB = Matter.Bodies.rectangle(200, 100, 80, 80, {
restitution: 1,
mass: 5
})
// 矩形C
let rectC = Matter.Bodies.rectangle(320, 100, 80, 80, {
restitution: 1,
mass: 10
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
Matter.Composite.add(engine.world, [rectA, rectB, rectC, ground])
静止 isStatic
前面几个例子中,空中的几个矩形都会往下掉,但地面却不会。
这是因为地面元素将 isStatic
设置为 true
了,所以元素就不会动了。
// 省略部分代码
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
关于基础元素的其他属性配置,可以看看 『Matter.js官方文档的 Body 内容』。
堆 stack
在 Matter.js
中允许你将多个物体组合在一起,以便更方便地管理和操作它们。这个方法叫做“堆 stack
”。
你可以将多个矩形放在一个 stack
中,然后一起移动它们,或者一起旋转它们,而不需要分别操作每个矩形。这可以大大简化代码,并提高代码的可维护性。
要创建一个 stack
,可以使用 Matter.Composites.stack
方法。
用法:Matter.Composites.stack(xx, yy, columns, rows, columnGap, rowGap, callback)
其中的参数作用:
-
xx
和yy
:stack
的起始位置。 -
columns
和rows
:stack
的列数和行数。 -
columnGap
: 相邻两个物体之间的列间隔。 -
rowGap
: 相邻两个物体之间的行间隔。 -
callback
: 回调函数,通常用于生成 stack 中的每个物体。
举个完整例子
<div id="c"></div>
<script src="../js/matter.js"></script>
<script>
let engine = Matter.Engine.create()
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400,
wireframes: false,
}
})
// 堆
// 起始位置是 (20, 20),一共6列3行,列间距10,行间距20
let stack = Matter.Composites.stack(20, 20, 6, 3, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 30, 30)
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 将堆和地面添加到世界里
Matter.Composite.add(engine.world, [stack, ground])
Matter.Render.run(render)
let runner = Matter.Runner.create()
Matter.Runner.run(runner, engine)
</script>
这个例子我只给堆和地面添加了注释,方便工友们寻找这段主要的代码。
在使用 stack
时,最后的用来创建物体的回调函数有 x
和 y
参数,这两个参数是 Matter.js
提供的,它会根据前面几个参数 (xx, yy, columns, rows, columnGap, rowGap)
来计算每次 x
和 y
的值是多少,而这个 x
和 y
通常用来定义图形元素的位置。
stack
更大的意义是方便我们集中管理堆中的元素,比如在上面这个例子中,要让所有立方体自身旋转30度,可以直接在回调函数里写上。
// 省略部分代码
let stack = Matter.Composites.stack(20, 20, 6, 3, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 30, 30, {
angle: Math.PI / 180 * 30, // 旋转30度
restitution: 0.5 // 添加一点回弹力
})
})
在这个例子中,我还给每个矩形增加了一点回弹力,让矩形在落地散开后的动画看上去更符合真实世界的逻辑。
除了能够方便地给每个矩形都添加属性外,你还可以给整个堆进行调整。
比如整体旋转30度(这个效果和上面的例子不一样!)。
// 省略部分代码
let stack = Matter.Composites.stack(20, 20, 6, 3, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 30, 30, {
restitution: 0.5 // 添加一点回弹力
})
})
// 整个堆旋转30度
Matter.Composite.rotate(stack, Math.PI / 180 * 30, { x: 0, y: 200 })
约束 Constraint
在 Matter.js
里,约束 Constraint
可以理解为将2个物体绑在一起。
生活中常见的例子跷跷板。
不好意思,放错图了,下面这张才对
一个简单的跷跷板分为2部分:横着的板和底座。
把这两部分绑定在一起就形成跷跷板。
在 Matter.js
中要实现这个功能,用到的就是约束 Constraint
。
先简单体验一下再说用法。
<div id="c"></div>
<script src="../js/matter.js"></script>
<script>
let engine = Matter.Engine.create()
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400,
wireframes: false,
}
})
// 板子A(红色)
let rectA = Matter.Bodies.rectangle(200, 330, 20, 100, {
isStatic: true,
render: {
fillStyle: '#f00'
},
collisionFilter: {
group: -1
}
})
// 板子B(蓝色)
let rectB = Matter.Bodies.rectangle(200, 330, 200, 20, {
render: {
fillStyle: '#00f'
},
collisionFilter: {
group: -1
}
})
// 创建旋转约束
let rotateConstraint = Matter.Constraint.create({
bodyA: rectA,
bodyB: rectB,
length: 0
})
// 矩形的堆
let stack = Matter.Composites.stack(20, 30, 4, 3, 10, 20, function (x, y) {
return Matter.Bodies.rectangle(x, y, 40, 20)
})
// 圆形的堆
let stack_circle = Matter.Composites.stack(220, 60, 3, 4, 10, 20, function (x, y) {
return Matter.Bodies.circle(x, y, 16)
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 将 蓝色和红色矩形、约束、矩形堆、圆形堆、地面 都添加到世界里
Matter.Composite.add(engine.world, [rectA, rectB, rotateConstraint, stack, stack_circle, ground])
Matter.Render.run(render)
let runner = Matter.Runner.create()
Matter.Runner.run(runner, engine)
</script>
在上面的例子中,我创建了1个跷跷板(由红色和蓝色矩形组合而成),1堆小矩形,1堆小圆形,1个地面。
小矩形堆和小圆形堆都做自由落体。
跷跷板使用了 Matter.Constraint.create
做约束处理,其中的参数 bodyA
和 bodyB
用来指定要约束的两个物体。length
表示约束的长度,设置为0的话,他们之间的约束点就没有任何挪动的空间,这就和跷跷板的原理一样了。
Matter.Constraint.create(options)
的配置对象包含以下属性:
-
options
:约束的选项。 -
options.bodyA
:类型为Matter.Body
,约束连接的第一个物体。 -
options.pointA
:类型为Matter.Vector
,约束连接的第一个物体上的点。 -
options.bodyB
:类型为Matter.Body
,约束连接的第二个物体。 -
options.pointB
:类型为Matter.Vector
,约束连接的第二个物体上的点。 -
options.length
:类型为number
,约束的初始长度。 -
options.stiffness
:类型为number
,约束的刚度系数。 -
options.damping
:类型为number
,约束的阻尼系数。 -
options.render
:约束的渲染选项。 -
options.render.visible
:类型为boolean
,表示约束是否可见,默认为true
。 -
options.render.lineWidth
:类型为number
,表示约束线条的宽度。 -
options.render.strokeStyle
:类型为string
,表示约束线条的颜色。
鼠标约束
这里所指的耗子约束是指给鼠标添加操作物体的功能。
要实现拖拽物体的功能,需要以下几个步骤:
- 创建鼠标实例
Matter.Mouse.create
。 - 给鼠标添加约束
Matter.MouseConstraint.create
。 - 将鼠标约束添加到物理引擎中。
<div id="c"></div>
<script src="../js/matter.js"></script>
<script>
let engine = Matter.Engine.create()
let render = Matter.Render.create({
element: document.getElementById('c'), // 绑定页面元素
engine: engine, // 绑定引擎
options: {
width: 400,
height: 400,
wireframes: false,
}
})
let box = Matter.Bodies.rectangle(80, 100, 80, 80, {
restitution: 0.3,
mass: 0.1
})
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 创建鼠标实例
let mouse = Matter.Mouse.create(render.canvas)
// 给鼠标添加约束
let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false // 默认为 true,会显示鼠标拖拽轨迹
}
}
})
// 将鼠标约束添加到物理引擎中
Matter.Composite.add(engine.world, [box, ground, mouseConstraint]);
Matter.Render.run(render)
let runner = Matter.Runner.create()
Matter.Runner.run(runner, engine)
</script>
事件监听
在 Matter.js
中,可以使用 Events.on
方法来监听各种事件,包括鼠标事件、碰撞事件等等。
常用鼠标事件
例如这样监听鼠标的各种事件(随便举点例子)
// 省略部分代码
// 创建一个 Mouse 实例
let mouse = Matter.Mouse.create(render.canvas)
let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse
})
// 监听鼠标事件
// 监听鼠标按下事件
Matter.Events.on(mouseConstraint, 'mousedown', function(event) {
console.log('按下')
})
// 监听鼠标移动事件
Matter.Events.on(mouseConstraint, "mousemove", function(event) {
console.log('移动')
})
// 监听鼠标抬起事件
Matter.Events.on(mouseConstraint, "mouseup", function(event) {
console.log('抬起')
})
// 监听鼠标拖拽刚体 - 开始拖拽
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
console.log('开始拖拽')
})
// 监听鼠标拖拽刚体 - 结束拖拽
Matter.Events.on(mouseConstraint, 'enddrag', function(event) {
console.log('结束拖拽')
})
Matter.Composite.add(engine.world, mouseConstraint)
监听碰撞
在 Matter.js
中,用 Matter.Events.on
去监听 collisionStart
事件就能知道物体的碰撞。
除了 collisionStart
外,还有其他监听周期。
-
collisionStart
:当两个物体开始碰撞时触发。 -
collisionActive
:当两个物体持续碰撞时触发。 -
collisionEnd
:当两个物体停止碰撞时触发。
我用 collisionStart
举例:
// 省略部分代码
// 创建一个矩形
var box = Matter.Bodies.rectangle(200, 100, 80, 80, {
restitution: 1
})
// 地面
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
// 添加刚体到引擎中
Matter.Composite.add(engine.world, [box, ground]);
// 监听碰撞事件
Matter.Events.on(engine, 'collisionStart', function(event) {
const pairs = event.pairs
pairs.forEach(pair => {
console.log(pair)
})
})
上面这个例子中,我给 box
设置了回弹力,它首次落地后回弹了2次,首次落地加2次回弹一共就触发了3次碰撞,所以在控制台输出了3次碰撞的结果。
其中,pairs
是指一对正在碰撞的物体。当两个物体相互碰撞时,它们就被组成为一个 pair
对象。
我们可以通过 event.pairs
属性来访问有关碰撞的更多信息。
代码仓库
点击下面的链接可以获取到本文所有完整demo,仓库的代码还会不定期更新~
⭐ Matter.js 案例仓库
推荐阅读
👍《眨个眼就学会了Pixi.js》
👍《P5.js 光速入门》
👍《Fabric.js从入门到膨胀》文章来源:https://www.toymoban.com/news/detail-711123.html
点赞 + 关注 + 收藏 = 学会了
代码仓库文章来源地址https://www.toymoban.com/news/detail-711123.html
到了这里,关于物理世界的互动之旅:Matter.js入门指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!