物理世界的互动之旅:Matter.js入门指南

本文简介

戴尬猴,我是德育处主任


欢迎来到《物理世界的互动之旅:Matter.js入门指南》。

本文将带您探索 Matter.js,一个强大而易于使用的 JavaScript 物理引擎库。

我将介绍 Matter.js 的基本概念,包括引擎、世界、物体和约束等。

本文还提供丰富的代码示例,帮助各位工友更好地理解如何使用 Matter.js 创建令人惊叹的物理场景(先画个饼吧~)。


本文是我的学习笔记和个人理解,在翻译和部分概念的理解上可能存在一点偏差,如果发现本文有什么错漏的地方,请自行调节呼吸频率。我懒得改~

本文前1000字都在讲一些基础概念,你觉得无聊可以先看后面的内容,看完再回来过一遍基础概念就行了。


Matter.js是什么?

在现实世界中,物理是无处不在的。从行星和恒星的运动到电子的运动,物理定律描述了我们周围几乎所有事物的运动和相互作用。

在计算机科学中,物理引擎是一种模拟物理现象的软件程序。它们通常用于创建物理游戏、虚拟现实和仿真等应用程序。物理引擎可以模拟各种现象,例如重力、碰撞和摩擦等。物理引擎通常是非常复杂的,因为它必须模拟现实世界中的各种效果。

在Web浏览器想模拟真实世界的物理现象其实也有很多库,2D方面有 Matter.jsP2.js 等,3D方面有 Cannon.jsammo.js 等。

而本文是将 Matter.js 的,所以我在这只会说 Matter.js 的好话。

Matter.js 是一个非常强大的 JavaScript 2D物理引擎,它能够帮助你在Web应用程序中实现逼真的物理效果。

Matter.js 提供了可定制的碰撞检测、重力、力学效应和运动控制等功能,让你可以快速、简单地构建交互式的物理模拟。无论是模拟游戏、建筑模型还是实验室实验,Matter.js 都可以满足你的需求。

Matter.js官网 ⚡️


基础概念

在学习 Matter.js 前,我们需要了解一些基础概念。由于本文是入门篇,所以我只介绍常用的基础概念。

模块名称说明
引擎(Engine)引擎 EngineMatter.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 基础概念。

先看效果。

file

从这个动图我们可以看出:

  1. 这个世界有2个正方形和一个地面(底部的长方形)。
  2. 正方形出现在空中,然后做自由落体运动。
  3. 左边的正方形碰到地面后出现了一点回弹。
  4. 右边的正方形落地前砸到左边的正方形,阻止了左边正方形的回弹,并且自己往右滚动了一下。

要使用 Matter.js 实现上面的效果,需要做以下几步:

  1. 创建容器。
  2. 引入 Matter.js
  3. 创建引擎。
  4. 创建渲染器,绑定画布上。
  5. 创建正方形和地面,并且让地面元素保持静止。
  6. 将创建好的元素添加到“世界”里(没错,你就是创世神~)。
  7. 最后,为这个世界添加“时间”属性,让它可以运转起来(Matter.Runner)。

上面所说的步骤还需要对应基础概念的表格配合理解。

转换成代码

<!-- 1. 创建容器 -->
<div id="c"></div><!-- 2. 引入 matter -->
<script src="../js/matter.js"></script>
<script>const Engine = Matter.Engineconst Render = Matter.Renderconst Bodies = Matter.Bodiesconst Composite = Matter.Compositeconst 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

file

// 省略部分代码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) 方法。

参数 xy 是矩形中心点的坐标,widthheight 是矩形的宽高。

如果创建一个 80*80 的矩形,希望它的左上角在 (0, 0) 的位置,那 xy 分别设置成 widthheight 的一半。

file

// 省略部分代码// 创建矩形
let rect = Matter.Bodies.rectangle(40, 40, 80, 80)// 将矩形添加到世界里
Matter.Composite.add(engine.world, rect)

圆形 circle

创建圆形的方法是 Matter.Bodies.circle(x, y, radius)

xy 是圆心坐标, radius 是半径。

file

// 省略部分代码// 创建圆形
let circle = Matter.Bodies.circle(40, 40, 40)// 将矩形添加到世界里
Matter.Composite.add(engine.world, circle)

梯形 trapezoid

创建梯形的方法是 Matter.Bodies.trapezoid(x, y, width, height, slope)

xy 定义了梯形的中心点坐标,widthheight 是梯形的宽高,slope 是斜率。

  • 当斜率 slope 大于0小于1时,梯形的上边小于下边。
  • 当斜率 slope 等于0时,梯形的上边和下边相等,看起来就是一个矩形。
  • 当斜率 slope 小于0时,上边大于下边。
  • 当斜率 slope 大于等于1时,就会呈现出三角形的样子。

file

// 省略部分代码let trapezoid = Matter.Bodies.trapezoid(200, 200, 80, 80, 0.5)

三角形 trapezoid

创建三角形的方法和梯形一样,只需将斜率 slope 设置成大于等于1的值即可。

file

// 省略部分代码let triangle = Matter.Bodies.trapezoid(200, 200, 80, 80, 1)

file

// 省略部分代码let triangle = Matter.Bodies.trapezoid(200, 200, 80, 80, 2)

正多边形 polygon

Matter.js 使用 Matter.Bodies.polygon(x, y, sides, radius) 创建正多边形。

注意,是正多边形!

参数 xy 是多边形中心点的坐标,sides 可以设置多边形的边的数量,radius 设置多边形的半径。

file

// 省略部分代码let polygon = Matter.Bodies.polygon(200, 200, 7, 40)

自定义多边形

使用Matter.js创建自定义多边形,可以使用 Matter.Bodies.fromVertices(x, y, vertexSets) 方法。

xy 定义多变西女中心的坐标,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 属性的值。例如,要将圆形的填充色设置为橙色,可以使用以下代码:

file

// 省略部分代码// 创建渲染器
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 可以设置边框的宽度。

file

// 省略部分代码// 创建渲染器
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.fillStylerender.strokeStyle 都支持 颜色关键字、#开头的十六进制、rgb、rgba等 颜色值。

但不支持 0x 开头的十六进制颜色。


贴图 render.sprite

一个优秀的前端必须懂得贴图,Matter.js 也提供了贴图功能。

只需要配置一下 render.sprite 即可。

我用矩形举例。

file

// 省略部分代码// 创建矩形
let rect = Matter.Bodies.rectangle(200, 200, 200,  200, {render: {sprite: { // 使用精灵texture: './monkey.jpg' // 图片纹理位置}}
})// 将所有物体添加到世界中
Matter.Composite.add(engine.world, rect)

缩放贴图 scale

如果需要设置贴图的宽高,还可以修改 xScaleyScale 属性。

但这两个属性只会影响贴图的尺寸,图形的真实尺寸并不会受到影响。

file

// 省略部分代码let rect = Matter.Bodies.rectangle(200, 200, 200,  200, {render: {sprite: {texture: './monkey.jpg',xScale: 0.5,yScale: 1.5}}
})

贴图偏移 offset

可以设置精灵图的 xOffsetyOffset

// 省略部分代码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.visiblefalse 时,元素会隐藏;反之元素就显示。render.visible 的默认值是 true

// 省略部分代码let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {render: {visible: false // 隐藏元素}
})

旋转 angle

angle 属性可以设置元素的旋转弧度。

为了方便理解,我还是更习惯用“角度”这个单位。

弧度转角度可以用这个公式:

Math.PI / 180 * 角度

file

// 省略部分代码// 矩形
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 这个属性可以让我们给指定物体配置具体的空气阻力。

file

// 省略部分代码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.10.51 ,数值越大,空气阻力就越大,自由落体的速度也就越慢。


回弹力 restitution

前面的例子中创建的物体都是没有弹力的,它们掉到地面时不会回弹。

如果希望物体有弹性,可以配置它的 restitution

file

// 省略部分代码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个质量不同的矩形,左边的矩形的质量最小,右边的最大。在回弹力相同的情况下,质量越小,回弹的程度就越大。

file

// 省略部分代码// 矩形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)

其中的参数作用:

  • xxyy: stack 的起始位置。
  • columnsrows: stack 的列数和行数。
  • columnGap: 相邻两个物体之间的列间隔。
  • rowGap: 相邻两个物体之间的行间隔。
  • callback: 回调函数,通常用于生成 stack 中的每个物体。

举个完整例子

file

<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,行间距20let 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 时,最后的用来创建物体的回调函数有 xy 参数,这两个参数是 Matter.js 提供的,它会根据前面几个参数 (xx, yy, columns, rows, columnGap, rowGap) 来计算每次 xy 的值是多少,而这个 xy 通常用来定义图形元素的位置。


stack 更大的意义是方便我们集中管理堆中的元素,比如在上面这个例子中,要让所有立方体自身旋转30度,可以直接在回调函数里写上。

file

// 省略部分代码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度(这个效果和上面的例子不一样!)。

file

// 省略部分代码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个物体绑在一起。

生活中常见的例子跷跷板。

file

不好意思,放错图了,下面这张才对

file

一个简单的跷跷板分为2部分:横着的板和底座。

把这两部分绑定在一起就形成跷跷板。

Matter.js 中要实现这个功能,用到的就是约束 Constraint

先简单体验一下再说用法。

file

<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 做约束处理,其中的参数 bodyAbodyB 用来指定要约束的两个物体。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,表示约束线条的颜色。


鼠标约束

这里所指的耗子约束是指给鼠标添加操作物体的功能。

要实现拖拽物体的功能,需要以下几个步骤:

  1. 创建鼠标实例 Matter.Mouse.create
  2. 给鼠标添加约束 Matter.MouseConstraint.create
  3. 将鼠标约束添加到物理引擎中。

file

<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 举例:

file

// 省略部分代码// 创建一个矩形
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.pairspairs.forEach(pair => {console.log(pair)})
})

上面这个例子中,我给 box 设置了回弹力,它首次落地后回弹了2次,首次落地加2次回弹一共就触发了3次碰撞,所以在控制台输出了3次碰撞的结果。

其中,pairs 是指一对正在碰撞的物体。当两个物体相互碰撞时,它们就被组成为一个 pair 对象。

我们可以通过 event.pairs 属性来访问有关碰撞的更多信息。



代码仓库

点击下面的链接可以获取到本文所有完整demo,仓库的代码还会不定期更新~

⭐ Matter.js 案例仓库



推荐阅读

👍《眨个眼就学会了Pixi.js》

👍《P5.js 光速入门》

👍《Fabric.js从入门到膨胀》


点赞 + 关注 + 收藏 = 学会了 代码仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/120023.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSS笔记-狂神

1、什么是CSS 如何学习 CSS是什么CSS怎么用&#xff08;快速入门&#xff09;CSS选择器&#xff08;重点难点&#xff09;美化网页&#xff08;文字&#xff0c;阴影&#xff0c;超链接&#xff0c;列表&#xff0c;渐变…&#xff09;盒子模型浮动定位网页动画&#xff08;特…

【IO面试题 二】、怎么用流打开一个大文件?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;怎么用流打开一个大文件…

手写效果流式响应(langchain+fastapi+js)

这是一个前后端完整可用的小项目 后端是 Python 的 FastAPI 框架&#xff0c;调用 langchain 进行 openai 的模型对话。前端是纯html css javascript&#xff0c;没调用任何第三方库&#xff0c;方便集成到 Vue React 等现有前端项目。 聊天界面&#xff1a; 效果就是提问之…

vue项目中定制化音频展示,wavesurfer.js基本使用

效果图&#xff1a; wavesurfer是一个可定制的音频波形可视化&#xff0c;建立在Audio API和HTML5 Canvas之上。 基本使用&#xff1a; <body><script src"https://unpkg.com/wavesurfer.js"></script><div id"waveform"></di…

软考系统架构师知识点集锦二:软件工程

一、考情分析 二、考点精讲 2.1 软件过程模型 &#xff08;1&#xff09;原型模型 典型的原型开发方法模型。适用于需求不明确的场景,可以帮助用户明确需求。可以分为[抛弃型原型]与[演化型原型] 原型模型两个阶段: 1、原型开发阶段;2、目标软件开发阶段。 &#x…

【深度学习】使用Pytorch实现的用于时间序列预测的各种深度学习模型类

深度学习模型类 简介按滑动时间窗口切割数据集模型类CNNGRULSTMMLPRNNTCNTransformerSeq2Seq 简介 本文所定义模型类的输入数据的形状shape统一为 [batch_size, time_step&#xff0c;n_features]&#xff0c;batch_size为批次大小&#xff0c;time_step为时间步长&#xff0c…

设计模式:桥接模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《适配器模式》 下一篇《装饰器模式》 简介&#xff1a; 桥接模式&#xff0c;它是一种结构型设计模式&#xff0c;它的主要目的是将抽象部分与具体实现部分分离&#xff0c;使它们都可以独立地变化。…

Mingw下载---运行vscodeC++文件

下载 下载网址&#xff1a; https://sourceforge.net/projects/mingw-w64/files/mingw-w64/mingw-w64-release/ 翻到最下面&#xff0c;选择win64的安装&#xff1a; 下载完&#xff0c;解压到没有空格和中文字符的路径。不然在vscode中运行不了C代码。

软考高级之系统架构师之数据流图和流程图

数据流图 概述 数据流图&#xff0c;DFD&#xff0c;用于表示业务信息系统中的数据流&#xff0c;它表达系统中的据传从输入到存储间所涉及的程序。采用图形方式来表达系统的逻辑功能、数据在系统内部的逻辑流向和逻辑变换过程&#xff0c;是结构化系统分析方法的主要表达工具…

源码推荐【源码好优多】

一、影视小程序 特点&#xff1a;可独立部署、消耗环境小、安全可靠。使用微信小程序技术开发。部署简单容易。该项目的部署需要具备微擎框架的开发以及部署能力 二、java博客管理系统 博客管理系统是一个融合线上、线下的网民在线交流管理信息化系统。它的使用为网民、运营者搭…

Flutter最全面试题大全

在理解这些问题之前&#xff0c;建议看一下Flutter架构原理&#xff0c;如下链接&#xff1a; https://blog.csdn.net/wang_yong_hui_1234/article/details/130427887?spm1001.2014.3001.5501 目录 一. 有个Text节点&#xff0c;由于文字内容过多&#xff0c;发生了溢出错误&…

三步,金蝶K3的数据可视化了

数据可视化的一大特点就是“一图胜千言”&#xff0c;没什么能比图表更直观展现数据的了。那&#xff0c;金蝶K3系统上那海量数据能不能也做成数据可视化报表&#xff1f;操作复杂吗&#xff0c;难度大吗&#xff1f; 换了别的软件来做&#xff0c;操作多、难度大是板上钉钉&a…

排序算法-堆积树排序法(HeapSort)

目录 排序算法-堆积树排序法&#xff08;HeapSort&#xff09; 1、说明 2、算法分析 3、C代码 排序算法-堆积树排序法&#xff08;HeapSort&#xff09; 1、说明 堆积树排序法是选择排序法的改进版&#xff0c;可以减少在选择排序法中的比较次数&#xff0c;进而减少排序…

计算机服务器中了devos勒索病毒怎么办?企业数据库被encryped

计算机网络技术的不断发展&#xff0c;为人们的生活提供了更多的帮助&#xff0c;但也为我们的企业带来了更多的数据安全威胁。近期&#xff0c;云天数据恢复中心收到很多企业的求助&#xff0c;企业的数据库遭到了devos后缀勒索病毒攻击&#xff0c;导致企业数据库无法打开&am…

TypeScript 基础学习

第一节&#xff1a;为什么使用ts? js 只能是动态类型检查&#xff0c;ts 是静态类型检查 第二节&#xff1a;优化编译 生成的配置文件名字叫tsconfig 第三节&#xff1a;变量类型 联合类型 可选属性 类型别名 接口 接口和类型别名的区别 接口扩展 类型扩展 类型断言&#…

为爱出发,与善同行丨纬创软件2023北京善行者圆满收官

2023年10月21日&#xff0c;北京善行者徒步活动在昌平正式开走。800支队伍3200名善行者队员进行32公里的公益行走。纬创软件组建「北京台协纬创软件队」&#xff0c;4名队员踏上32公里的征程&#xff0c;通过徒步筹款的方式传递善行理念&#xff0c;为贫困山区的孩子们建立“爱…

Linux redis 安装

1、解压 tar -zxvf redis-5.0.10.tar.gz 2、cd /data/redis-5.0.10 文件夹 3、make 等待make命令执行完成即可。 make命令报错&#xff1a;cc 未找到命令&#xff0c;系统中缺少gcc&#xff0c;执行命令安装 gcc&#xff1a; yum -y install gcc automake autocon…

内网穿透的应用-Linux JumpServer堡垒机:安全远程访问解决方案

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

C#,数值计算——分类与推理,基座向量机(SVM,Support Vector Machines)的计算方法与源程序

把 Support Vector Machines 翻译成 支持向量机 是书呆子翻译。基座向量机 不好吗。 1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Support Vector Machines /// </summary> public class Svm { priv…

【SpringCloudNetflix】一图理解Spring Cloud Netflix解决了那些微服务问题?

什么是微服务理解&#xff1a; SpringCloudNetflix解决的问题理解&#xff1a; SpringCloudNetflix核心点&#xff1a; 注册中心&#xff1a;Eureka负载均衡&#xff1a;Ribbon、Feign服务熔断&#xff1a;Hystrix服务降级&#xff1a;Hystrix服务监控&#xff1a;Hystrix Da…