本文簡介
戴尬猴,我是德育處主任
歡迎來到《物理世界的互動之旅:Matter.js入門指南》。
本文將帶您探索 Matter.js
,一個強大而易于使用的 JavaScript
物理引擎庫。
我將介紹 Matter.js
的基本概念,包括引擎、世界、物體和約束等。
本文還提供豐富的代碼示例,幫助各位工友更好地理解如何使用 Matter.js
創(chuàng)建令人驚嘆的物理場景(先畫個餅吧~)。
本文是我的學(xué)習(xí)筆記和個人理解,在翻譯和部分概念的理解上可能存在一點偏差,如果發(fā)現(xiàn)本文有什么錯漏的地方,請自行調(diào)節(jié)呼吸頻率。我懶得改~
本文前1000字都在講一些基礎(chǔ)概念,你覺得無聊可以先看后面的內(nèi)容,看完再回來過一遍基礎(chǔ)概念就行了。
Matter.js是什么?
在現(xiàn)實世界中,物理是無處不在的。從行星和恒星的運動到電子的運動,物理定律描述了我們周圍幾乎所有事物的運動和相互作用。
在計算機科學(xué)中,物理引擎是一種模擬物理現(xiàn)象的軟件程序。它們通常用于創(chuàng)建物理游戲、虛擬現(xiàn)實和仿真等應(yīng)用程序。物理引擎可以模擬各種現(xiàn)象,例如重力、碰撞和摩擦等。物理引擎通常是非常復(fù)雜的,因為它必須模擬現(xiàn)實世界中的各種效果。
在Web瀏覽器想模擬真實世界的物理現(xiàn)象其實也有很多庫,2D方面有 Matter.js
、P2.js
等,3D方面有 Cannon.js
、ammo.js
等。
而本文是將 Matter.js
的,所以我在這只會說 Matter.js
的好話。
Matter.js
是一個非常強大的 JavaScript
2D物理引擎,它能夠幫助你在Web應(yīng)用程序中實現(xiàn)逼真的物理效果。
Matter.js
提供了可定制的碰撞檢測、重力、力學(xué)效應(yīng)和運動控制等功能,讓你可以快速、簡單地構(gòu)建交互式的物理模擬。無論是模擬游戲、建筑模型還是實驗室實驗,Matter.js
都可以滿足你的需求。
Matter.js官網(wǎng) ??
基礎(chǔ)概念
在學(xué)習(xí) Matter.js
前,我們需要了解一些基礎(chǔ)概念。由于本文是入門篇,所以我只介紹常用的基礎(chǔ)概念。
模塊名稱 | 說明 |
---|---|
引擎(Engine) | 引擎 Engine 是 Matter.js 的核心組件,用于管理物理世界中的所有對象、計算物體的運動和相互作用。用來模擬真實環(huán)境的。 |
渲染器(Render) | 渲染器 Render 用于將物理世界中的對象可視化。意思就是它能將物體渲染到屏幕上。 |
復(fù)合體(Composite) | 是包含多個剛體和約束的容器,它們可以作為單個物理對象進行操作。 |
剛體(Body) | 表示具有物理屬性的實體,如形狀、質(zhì)量和速度等。剛體可以是各種形狀,例如矩形、圓形、多邊形等。 |
約束(Constraint) | 用于約束剛體的相對運動,例如讓兩個剛體之間的距離保持不變、限制旋轉(zhuǎn)等。 |
循環(huán)模塊 (Runner) |
Runner 用于管理和控制物理引擎的主循環(huán)。 |
我用自己的話粗略總結(jié)一下(但我感覺我總結(jié)得不太正確,工友們有更好的理解可以到評論區(qū)留句話,沒什么好說的也可以寫句“到此一游”)。
引擎 Engine
可以模擬我們真實世界的一些物理法則。
剛體 Body
可以粗略理解為現(xiàn)實世界中的物體,比如一個球、一張凳子。
復(fù)合體 Composite
是一個容器,可以將多個物體整合起來,讓它們產(chǎn)生聯(lián)系。比如創(chuàng)建了一個球(剛體),然后用 Composite
將球和引擎連接起來,這樣球就會收到物理規(guī)則的影響了。
渲染器 Render
就是個眼睛的作用,它能幫助我們看到 Matter.js
創(chuàng)建出來的世界。
約束 Constraint
就是約束,比如一個蹺蹺板由一根很長的模板和一個底座組成,底座固定在地面,木板的中間鎖定在底座上面,這個鎖定動作就是約束。正因為有這個約束,所以蹺蹺板才能成為蹺蹺板。
循環(huán)模塊 Runner
可以粗略的理解為現(xiàn)實世界中的時間。如果沒有循環(huán)模塊,頁面的所有元素都是定格的。你可以理解為現(xiàn)實世界沒有時間的話,整個世界都會靜止。
以上就是我覺得 Matter.js
入門階段需要了解的一些基礎(chǔ)概念。
除此之外其實還需要掌握一些基礎(chǔ)物理概念,比如知道什么是碰撞,什么事摩擦力、阻力、重力等。這類概念會在接下來的案例中講解。
安裝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 應(yīng)用
這個例子是 Matter.js 官方的起步案例
,通過這個例子你可以快速理解到前面講的 Matter.js
基礎(chǔ)概念。
先看效果。
從這個動圖我們可以看出:
- 這個世界有2個正方形和一個地面(底部的長方形)。
- 正方形出現(xiàn)在空中,然后做自由落體運動。
- 左邊的正方形碰到地面后出現(xiàn)了一點回彈。
- 右邊的正方形落地前砸到左邊的正方形,阻止了左邊正方形的回彈,并且自己往右滾動了一下。
要使用 Matter.js
實現(xiàn)上面的效果,需要做以下幾步:
- 創(chuàng)建容器。
- 引入
Matter.js
。 - 創(chuàng)建引擎。
- 創(chuàng)建渲染器,綁定畫布上。
- 創(chuàng)建正方形和地面,并且讓地面元素保持靜止。
- 將創(chuàng)建好的元素添加到“世界”里(沒錯,你就是創(chuàng)世神~)。
- 最后,為這個世界添加“時間”屬性,讓它可以運轉(zhuǎn)起來(
Matter.Runner
)。
上面所說的步驟還需要對應(yīng)基礎(chǔ)概念的表格配合理解。
轉(zhuǎn)換成代碼
<!-- 1. 創(chuàng)建容器 -->
<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. 創(chuàng)建引擎
let engine = Engine.create()
// 4. 創(chuàng)建渲染器,并將引擎連接到畫布上
let render = Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
})
// 5-1. 創(chuàng)建兩個正方形
let boxA = Bodies.rectangle(400, 200, 80, 80)
let boxB = Bodies.rectangle(450, 50, 80, 80)
// 5-2. 創(chuàng)建地面,將isStatic設(shè)為true,表示物體靜止
let ground = Bodies.rectangle(400, 610, 810, 60, { isStatic: true })
// 6. 將所有物體添加到世界中
Composite.add(engine.world, [boxA, boxB, ground])
// 7. 執(zhí)行渲染操作
Render.run(render)
// 8. 創(chuàng)建運行方法
var runner = Runner.create()
// 9. 運行渲染器
Runner.run(runner, engine)
</script>
我們使用 Engine
創(chuàng)建引擎,Matter.js
的這個引擎默認(rèn)幫我們定義好這個世界的基本運行規(guī)律。
然后我們使用 Render
創(chuàng)建渲染器,這個渲染器可以將引擎和頁面綁定在一起。
Bodies
是剛體的意思,用它來創(chuàng)建物體的,本例就創(chuàng)建了2個正方形和1個地面。
Composite
就是前面講到的復(fù)合體,它可以讓世界和物體產(chǎn)生關(guān)聯(lián),也就是說可以將物體添加到世界中。
最后通過 Render
讓這個世界有了“時間”的概念,物體也會根據(jù)世界的規(guī)則在時間的運行下產(chǎn)生運動。
上面的代碼也許你還不理解每個方法的具體使用方式,但結(jié)合我前面的分析,我相信你已經(jīng)大概了解 Matter.js
“創(chuàng)造世界”的基本流程(也許聽完我的解析后更懵了)。
渲染器
在前面的例子中,我們使用 Matter.Render.create
將畫布和頁面元素綁定在一起。此時默認(rèn)的畫布尺寸是 800px * 600px
。
// 省略部分代碼
let render = Matter.Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
})
其實它還支持其他屬性配置,可以設(shè)置畫布寬高等信息。
設(shè)置畫布寬高
使用 Matter.Render.create
時還能傳入 options
參數(shù)。
// 省略部分代碼
let render = Matter.Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
options: {
width: 400,
height: 400
}
})
關(guān)閉線框模式
Matter.js
創(chuàng)建的形狀默認(rèn)是線框模式的,你可以手動關(guān)閉這個模式,Matter.js
就會自動幫你填充一些顏色到基礎(chǔ)圖形上。
關(guān)閉線框模式的方式是將 wireframes
設(shè)置為 false
。
// 省略部分代碼
let render = Matter.Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
options: {
wireframes: false
}
})
其他代碼,包括創(chuàng)建圖形的代碼都和“起步,第一個 Matter.js 應(yīng)用”一樣。
options
還支持其他的配置,有興趣的工友可以看看 文檔??。
圖形元素
Matter.js
支持多種基礎(chǔ)圖形,包括矩形、圓形、三角形、梯形、多邊形等。這些圖形還支持配置顏色、摩擦力等屬性。
基礎(chǔ)圖形
先說說基礎(chǔ)。
在 Matter.js
文檔中你會留意到創(chuàng)建物體使用的是 Body
或者 Bodies
,翻譯成中文就是“剛體”。
在物理世界中,剛體是指在運動中和受力作用后,形狀和大小不變,而且內(nèi)部各點的相對位置不變的物體。
在 Matter.js
中,剛體(Body
) 是一種物理對象,它具有質(zhì)量、位置、速度、加速度和形狀等屬性,可以被添加到物理世界中并受到物理引擎的模擬。例如矩形和圓形。
在入門階段,我們可以使用 Bodies
創(chuàng)建基礎(chǔ)圖形。
矩形 rectangle
前面我們已經(jīng)使用過矩形了。在這小節(jié)粗略講解一下創(chuàng)建矩形的一些必傳參數(shù)。
創(chuàng)建矩形使用的是 Matter.Bodies.rectangle(x, y, width, height)
方法。
參數(shù) x
和 y
是矩形中心點的坐標(biāo),width
和 height
是矩形的寬高。
如果創(chuàng)建一個 80*80 的矩形,希望它的左上角在 (0, 0) 的位置,那 x
和 y
分別設(shè)置成 width
和 height
的一半。
// 省略部分代碼
// 創(chuàng)建矩形
let rect = Matter.Bodies.rectangle(40, 40, 80, 80)
// 將矩形添加到世界里
Matter.Composite.add(engine.world, rect)
圓形 circle
創(chuàng)建圓形的方法是 Matter.Bodies.circle(x, y, radius)
。
x
和 y
是圓心坐標(biāo), radius
是半徑。
// 省略部分代碼
// 創(chuàng)建圓形
let circle = Matter.Bodies.circle(40, 40, 40)
// 將矩形添加到世界里
Matter.Composite.add(engine.world, circle)
梯形 trapezoid
創(chuàng)建梯形的方法是 Matter.Bodies.trapezoid(x, y, width, height, slope)
。
x
和 y
定義了梯形的中心點坐標(biāo),width
和 height
是梯形的寬高,slope
是斜率。
- 當(dāng)斜率
slope
大于0小于1時,梯形的上邊小于下邊。 - 當(dāng)斜率
slope
等于0時,梯形的上邊和下邊相等,看起來就是一個矩形。 - 當(dāng)斜率
slope
小于0時,上邊大于下邊。 - 當(dāng)斜率
slope
大于等于1時,就會呈現(xiàn)出三角形的樣子。
// 省略部分代碼
let trapezoid = Matter.Bodies.trapezoid(200, 200, 80, 80, 0.5)
三角形 trapezoid
創(chuàng)建三角形的方法和梯形一樣,只需將斜率 slope
設(shè)置成大于等于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)
創(chuàng)建正多邊形。
注意,是正多邊形!
參數(shù) x
和 y
是多邊形中心點的坐標(biāo),sides
可以設(shè)置多邊形的邊的數(shù)量,radius
設(shè)置多邊形的半徑。
// 省略部分代碼
let polygon = Matter.Bodies.polygon(200, 200, 7, 40)
自定義多邊形
使用Matter.js創(chuàng)建自定義多邊形,可以使用 Matter.Bodies.fromVertices(x, y, vertexSets)
方法。
x
和 y
定義多變西女中心的坐標(biāo),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)
圖形狀態(tài)和屬性配置
前面使用 Matter.bodies
創(chuàng)建的圖形時,可以在最后加多一個對象參數(shù),這個參數(shù)可以配置圖形的狀態(tài)和屬性。
填充色 render.fillStyle
如果您想為Matter.js中的形狀添加填充色,可以在 render 屬性中配置 fillStyle
屬性的值。例如,要將圓形的填充色設(shè)置為橙色,可以使用以下代碼:
// 省略部分代碼
// 創(chuàng)建渲染器
let render = Matter.Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
options: {
width: 400,
height: 400,
wireframes: false, // 關(guān)閉線框模式
}
})
// 省略部分代碼
// 創(chuàng)建矩形
let rect = Matter.Bodies.rectangle(200, 200, 80, 80, {
render: {
fillStyle: 'orange'
}
})
需要注意的是,使用填充色功能時,要關(guān)掉渲染器的線框模式。
邊框顏色和線寬 render.strokeStyle & render.lineWidth
使用 render.strokeStyle
可以設(shè)置邊框顏色,使用 render.lineWidth
可以設(shè)置邊框的寬度。
// 省略部分代碼
// 創(chuàng)建渲染器
let render = Matter.Render.create({
element: document.getElementById('c'), // 綁定頁面元素
engine: engine, // 綁定引擎
options: {
width: 400,
height: 400,
wireframes: false, // 關(guān)閉線框模式
}
})
// 省略部分代碼
// 創(chuàng)建矩形
let rect = Matter.Bodies.rectangle(200, 200, 80, 80, {
render: {
strokeStyle: '#3490de', // 設(shè)置邊框顏色
lineWidth: 20 // 設(shè)置邊框?qū)挾? }
})
render.fillStyle
和 render.strokeStyle
都支持 顏色關(guān)鍵字、#開頭的十六進制、rgb、rgba等 顏色值。
但不支持 0x
開頭的十六進制顏色。
貼圖 render.sprite
一個優(yōu)秀的前端必須懂得貼圖,Matter.js
也提供了貼圖功能。
只需要配置一下 render.sprite
即可。
我用矩形舉例。
// 省略部分代碼
// 創(chuàng)建矩形
let rect = Matter.Bodies.rectangle(200, 200, 200, 200, {
render: {
sprite: { // 使用精靈
texture: './monkey.jpg' // 圖片紋理位置
}
}
})
// 將所有物體添加到世界中
Matter.Composite.add(engine.world, rect)
縮放貼圖 scale
如果需要設(shè)置貼圖的寬高,還可以修改 xScale
和 yScale
屬性。
但這兩個屬性只會影響貼圖的尺寸,圖形的真實尺寸并不會受到影響。
// 省略部分代碼
let rect = Matter.Bodies.rectangle(200, 200, 200, 200, {
render: {
sprite: {
texture: './monkey.jpg',
xScale: 0.5,
yScale: 1.5
}
}
})
貼圖偏移 offset
可以設(shè)置精靈圖的 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
當(dāng) render.visible
為 false
時,元素會隱藏;反之元素就顯示。render.visible
的默認(rèn)值是 true
。
// 省略部分代碼
let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {
render: {
visible: false // 隱藏元素
}
})
旋轉(zhuǎn) angle
angle
屬性可以設(shè)置元素的旋轉(zhuǎn)弧度。
為了方便理解,我還是更習(xí)慣用“角度”這個單位。
弧度轉(zhuǎn)角度可以用這個公式:
Math.PI / 180 * 角度
// 省略部分代碼
// 矩形
let rect = Matter.Bodies.rectangle(80, 100, 80, 80, {
angle: Math.PI / 180 * 45
})
上面這段代碼創(chuàng)建了一個矩形,并且讓他旋轉(zhuǎn)45度。結(jié)合上面的公式應(yīng)該比較容易理解。
空氣阻力 frictionAir
前面簡單的介紹了一下基礎(chǔ)圖形怎么填充顏色、怎么使用貼圖,這些都前菜。
Matter.js
真正的亮點是物理引擎。
在前面有講到,要讓物理引擎動起來,需要用到下面這段代碼
// 省略部分代碼
// 創(chuàng)建運行方法
let runner = Runner.create()
// 運行渲染器
Runner.run(runner, engine)
如果忘了,可以看看前面的 “起步,第一個 Matter.js 應(yīng)用” 這章節(jié)。
先介紹一下空氣阻力。
我們知道,在地球上,當(dāng)一個物體做自由落體運動時,會受到空氣阻力的影響。
Matter.js
提供了 frictionAir
這個屬性可以讓我們給指定物體配置具體的空氣阻力。
// 省略部分代碼
let rectA = Matter.Bodies.rectangle(80, 100, 80, 80, {
frictionAir: 0.1 // 設(shè)置空氣阻力
})
let rectB = Matter.Bodies.rectangle(200, 100, 80, 80, {
frictionAir: 0.5 // 設(shè)置空氣阻力
})
let rectC = Matter.Bodies.rectangle(320, 100, 80, 80, {
frictionAir: 1 // 設(shè)置空氣阻力
})
// 地面
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
,數(shù)值越大,空氣阻力就越大,自由落體的速度也就越慢。
回彈力 restitution
前面的例子中創(chuàng)建的物體都是沒有彈力的,它們掉到地面時不會回彈。
如果希望物體有彈性,可以配置它的 restitution
。
// 省略部分代碼
let rectA = Matter.Bodies.rectangle(80, 100, 80, 80, {
restitution: 0 // 設(shè)置彈力
})
let rectB = Matter.Bodies.rectangle(200, 100, 80, 80, {
restitution: 1 // 設(shè)置彈力
})
let rectC = Matter.Bodies.rectangle(320, 100, 80, 80, {
restitution: 1.2 // 設(shè)置彈力
})
// 地面
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表示碰撞后完全反彈。
如果反彈系數(shù)大于1,就意味著碰撞后物體的能量增加,這是不符合物理規(guī)律的。
但如果你在做游戲,在處理游戲角色的某些技能時也可以讓回彈力超出1。畢竟這是你的世界。
質(zhì)量 mass
在初中物理課上我們知道,質(zhì)量越大,慣性越大。也就是說物體更難改變它的狀態(tài)(靜止或運動狀態(tài))。當(dāng)施加力或者撞擊物體時,質(zhì)量越大的物體會更難加速或者減速,需要更長的時間來達(dá)到相同的速度或者停止。而質(zhì)量越小的物體則更容易改變它的狀態(tài),可以更快地加速或減速。
在 Matter.js
中,碰撞響應(yīng)的計算是基于物體的質(zhì)量和速度等參數(shù)的。比如,當(dāng)兩個物體相撞時,質(zhì)量越大的物體會對速度的改變產(chǎn)生更小的影響,而質(zhì)量越小的物體會對速度的改變產(chǎn)生更大的影響。
舉個例子,我在畫布中創(chuàng)建3個質(zhì)量不同的矩形,左邊的矩形的質(zhì)量最小,右邊的最大。在回彈力相同的情況下,質(zhì)量越小,回彈的程度就越大。
// 省略部分代碼
// 矩形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
設(shè)置為 true
了,所以元素就不會動了。
// 省略部分代碼
let ground = Matter.Bodies.rectangle(200, 390, 400, 20, {
isStatic: true,
render: {
fillStyle: '#cccccc'
}
})
關(guān)于基礎(chǔ)元素的其他屬性配置,可以看看 『Matter.js官方文檔的 Body 內(nèi)容』。
堆 stack
在 Matter.js
中允許你將多個物體組合在一起,以便更方便地管理和操作它們。這個方法叫做“堆 stack
”。
你可以將多個矩形放在一個 stack
中,然后一起移動它們,或者一起旋轉(zhuǎn)它們,而不需要分別操作每個矩形。這可以大大簡化代碼,并提高代碼的可維護性。
要創(chuàng)建一個 stack
,可以使用 Matter.Composites.stack
方法。
用法:Matter.Composites.stack(xx, yy, columns, rows, columnGap, rowGap, callback)
其中的參數(shù)作用:
-
xx
和yy
:stack
的起始位置。 -
columns
和rows
:stack
的列數(shù)和行數(shù)。 -
columnGap
: 相鄰兩個物體之間的列間隔。 -
rowGap
: 相鄰兩個物體之間的行間隔。 -
callback
: 回調(diào)函數(shù),通常用于生成 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
時,最后的用來創(chuàng)建物體的回調(diào)函數(shù)有 x
和 y
參數(shù),這兩個參數(shù)是 Matter.js
提供的,它會根據(jù)前面幾個參數(shù) (xx, yy, columns, rows, columnGap, rowGap)
來計算每次 x
和 y
的值是多少,而這個 x
和 y
通常用來定義圖形元素的位置。
stack
更大的意義是方便我們集中管理堆中的元素,比如在上面這個例子中,要讓所有立方體自身旋轉(zhuǎn)30度,可以直接在回調(diào)函數(shù)里寫上。
// 省略部分代碼
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, // 旋轉(zhuǎn)30度
restitution: 0.5 // 添加一點回彈力
})
})
在這個例子中,我還給每個矩形增加了一點回彈力,讓矩形在落地散開后的動畫看上去更符合真實世界的邏輯。
除了能夠方便地給每個矩形都添加屬性外,你還可以給整個堆進行調(diào)整。
比如整體旋轉(zhuǎn)30度(這個效果和上面的例子不一樣?。?/p>
// 省略部分代碼
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 // 添加一點回彈力
})
})
// 整個堆旋轉(zhuǎn)30度
Matter.Composite.rotate(stack, Math.PI / 180 * 30, { x: 0, y: 200 })
約束 Constraint
在 Matter.js
里,約束 Constraint
可以理解為將2個物體綁在一起。
生活中常見的例子蹺蹺板。
不好意思,放錯圖了,下面這張才對
一個簡單的蹺蹺板分為2部分:橫著的板和底座。
把這兩部分綁定在一起就形成蹺蹺板。
在 Matter.js
中要實現(xiàn)這個功能,用到的就是約束 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(藍(lán)色)
let rectB = Matter.Bodies.rectangle(200, 330, 200, 20, {
render: {
fillStyle: '#00f'
},
collisionFilter: {
group: -1
}
})
// 創(chuàng)建旋轉(zhuǎn)約束
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'
}
})
// 將 藍(lán)色和紅色矩形、約束、矩形堆、圓形堆、地面 都添加到世界里
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>
在上面的例子中,我創(chuàng)建了1個蹺蹺板(由紅色和藍(lán)色矩形組合而成),1堆小矩形,1堆小圓形,1個地面。
小矩形堆和小圓形堆都做自由落體。
蹺蹺板使用了 Matter.Constraint.create
做約束處理,其中的參數(shù) bodyA
和 bodyB
用來指定要約束的兩個物體。length
表示約束的長度,設(shè)置為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
,約束的剛度系數(shù)。 -
options.damping
:類型為number
,約束的阻尼系數(shù)。 -
options.render
:約束的渲染選項。 -
options.render.visible
:類型為boolean
,表示約束是否可見,默認(rèn)為true
。 -
options.render.lineWidth
:類型為number
,表示約束線條的寬度。 -
options.render.strokeStyle
:類型為string
,表示約束線條的顏色。
鼠標(biāo)約束
這里所指的耗子約束是指給鼠標(biāo)添加操作物體的功能。
要實現(xiàn)拖拽物體的功能,需要以下幾個步驟:
- 創(chuàng)建鼠標(biāo)實例
Matter.Mouse.create
。 - 給鼠標(biāo)添加約束
Matter.MouseConstraint.create
。 - 將鼠標(biāo)約束添加到物理引擎中。
<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'
}
})
// 創(chuàng)建鼠標(biāo)實例
let mouse = Matter.Mouse.create(render.canvas)
// 給鼠標(biāo)添加約束
let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: {
visible: false // 默認(rèn)為 true,會顯示鼠標(biāo)拖拽軌跡
}
}
})
// 將鼠標(biāo)約束添加到物理引擎中
Matter.Composite.add(engine.world, [box, ground, mouseConstraint]);
Matter.Render.run(render)
let runner = Matter.Runner.create()
Matter.Runner.run(runner, engine)
</script>
事件監(jiān)聽
在 Matter.js
中,可以使用 Events.on
方法來監(jiān)聽各種事件,包括鼠標(biāo)事件、碰撞事件等等。
常用鼠標(biāo)事件
例如這樣監(jiān)聽鼠標(biāo)的各種事件(隨便舉點例子)
// 省略部分代碼
// 創(chuàng)建一個 Mouse 實例
let mouse = Matter.Mouse.create(render.canvas)
let mouseConstraint = Matter.MouseConstraint.create(engine, {
mouse: mouse
})
// 監(jiān)聽鼠標(biāo)事件
// 監(jiān)聽鼠標(biāo)按下事件
Matter.Events.on(mouseConstraint, 'mousedown', function(event) {
console.log('按下')
})
// 監(jiān)聽鼠標(biāo)移動事件
Matter.Events.on(mouseConstraint, "mousemove", function(event) {
console.log('移動')
})
// 監(jiān)聽鼠標(biāo)抬起事件
Matter.Events.on(mouseConstraint, "mouseup", function(event) {
console.log('抬起')
})
// 監(jiān)聽鼠標(biāo)拖拽剛體 - 開始拖拽
Matter.Events.on(mouseConstraint, 'startdrag', function(event) {
console.log('開始拖拽')
})
// 監(jiān)聽鼠標(biāo)拖拽剛體 - 結(jié)束拖拽
Matter.Events.on(mouseConstraint, 'enddrag', function(event) {
console.log('結(jié)束拖拽')
})
Matter.Composite.add(engine.world, mouseConstraint)
監(jiān)聽碰撞
在 Matter.js
中,用 Matter.Events.on
去監(jiān)聽 collisionStart
事件就能知道物體的碰撞。
除了 collisionStart
外,還有其他監(jiān)聽周期。
-
collisionStart
:當(dāng)兩個物體開始碰撞時觸發(fā)。 -
collisionActive
:當(dāng)兩個物體持續(xù)碰撞時觸發(fā)。 -
collisionEnd
:當(dāng)兩個物體停止碰撞時觸發(fā)。
我用 collisionStart
舉例:
// 省略部分代碼
// 創(chuàng)建一個矩形
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]);
// 監(jiān)聽碰撞事件
Matter.Events.on(engine, 'collisionStart', function(event) {
const pairs = event.pairs
pairs.forEach(pair => {
console.log(pair)
})
})
上面這個例子中,我給 box
設(shè)置了回彈力,它首次落地后回彈了2次,首次落地加2次回彈一共就觸發(fā)了3次碰撞,所以在控制臺輸出了3次碰撞的結(jié)果。
其中,pairs
是指一對正在碰撞的物體。當(dāng)兩個物體相互碰撞時,它們就被組成為一個 pair
對象。
我們可以通過 event.pairs
屬性來訪問有關(guān)碰撞的更多信息。
代碼倉庫
點擊下面的鏈接可以獲取到本文所有完整demo,倉庫的代碼還會不定期更新~
? Matter.js 案例倉庫
推薦閱讀
??《眨個眼就學(xué)會了Pixi.js》
??《P5.js 光速入門》
??《Fabric.js從入門到膨脹》文章來源:http://www.zghlxwxcb.cn/news/detail-711123.html
點贊 + 關(guān)注 + 收藏 = 學(xué)會了
代碼倉庫文章來源地址http://www.zghlxwxcb.cn/news/detail-711123.html
到了這里,關(guān)于物理世界的互動之旅:Matter.js入門指南的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!