写在开头
哈喽呀!😃
今天是2024年6月11号,坏消息是端午假期刚结束,好消息是这周只要上4天,有盼头。👻
近来,广州一直下雨,人已发霉🤢!感觉这场雨好像下了好久好久,一个月?两个月?已经记不得了。。。
希望赶紧放晴吧🔆,快能养蘑菇了都🍄🍄🍄。
回到正题,本文将分享一篇关于 Matter.js 的内容,请诸君按需食用。
安装依赖
Matter.js 是一个 2D 网络物理引擎。
(听起来是不是很厉害的样子?简介越短,能力越强。💪)
确实很强,可以先瞧瞧示例:传送门
官方文档:传送门
安装依赖:
npm install matter-js matter-wrap
或者使用 CDN :
<script src="https://unpkg.com/matter-js@0.19.0/build/matter.js"></script>
<script src="https://unpkg.com/matter-wrap@0.2.0/build/matter-wrap.js"></script>
这次咱们会使用到 matter-js 与 matter-wrap 两个包,关于它们的一些细节使用情况这里就不过多介绍了,直接推荐掘友写得文章:
matter-js 参考文章:传送门
matter-wrap 参考文章:传送门
看完文章应该就能了解个大概哈😁,或者你直接看看官方文档也可以,主要就是了解 Engine、Render、Runner 等几个关键对象,后面使用到小编也会写明详细注释的,咱们直接来看看具体实现过程,冲!
正文内容
先进行布局:
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: #f2f2ff;
}
canvas {
position: fixed;
z-index: -1;
top: 0;
left: 0;
}
</style>
</head>
<body>
<div class="content">
很长很长的内容........
</div>
<canvas id="bg"></canvas>
</body>
</html>
引入 matter-js 与 matter-wrap 两个包,这里就直接使用 CDN 引入了:
<script src="https://unpkg.com/matter-js@0.19.0/build/matter.js"></script>
<script src="https://unpkg.com/matter-wrap@0.2.0/build/matter-wrap.js"></script>
初始化 matter-js 库,随便创建几个球玩玩:
<script>
window.addEventListener('DOMContentLoaded', () => {
// 获取网页宽高
const screenWidth = document.documentElement.clientWidth;
const screenHeight = document.documentElement.clientHeight;
// 创建引擎
const engine = Matter.Engine.create();
// y轴的重力设置成0,让小球固定在设置的位置上,否则会往下掉落
engine.world.gravity.y = 0;
// 创建渲染器
let render = Matter.Render.create({
canvas: document.getElementById('bg'),
engine: engine,
options: {
width: screenWidth,
height: screenHeight,
background: 'transparent',
// 使用实心填充渲染
wireframes: false,
}
});
// 执行渲染器
Matter.Render.run(render);
// 创建运行方法对象
const runner = Matter.Runner.create();
Matter.Runner.run(runner, engine);
// 创建三个小球
Matter.World.add(engine.world, [
Matter.Bodies.circle(100, 100, 20),
Matter.Bodies.circle(200, 200, 20),
Matter.Bodies.circle(300, 300, 20),
]);
});
</script>
效果:
万事开头难,能搞懂这个小案例,接下来就是不断进行变种与扩展就行😉。
比如,我们让其生成一定数量的小球,小球的大小与颜色给它随机产生,使它更有趣一点。
// ...
// 全部小球
const balls = [];
// 小球数量
const total = 15;
for (let i = 0; i <= total; i++) {
balls.push(createBall(screenWidth, screenHeight));
}
// 渲染全部小球
Matter.World.add(engine.world, balls);
/** @name 生成小球 **/
function createBall(width, height) {
// 小球的大小
const x = randomNumber(0, width);
const y = randomNumber(0, height);
const radius = randomNumber(30, 60);
// 小球的颜色
const colors = ['#8A2BE2', '#E74C3C', '#1E90FF', '#FFA500', '#FF007F'];
const color = colors[Math.floor(randomNumber(0, colors.length))];
// 生成一个小球
return Matter.Bodies.circle(x, y, radius, {
render: {
fillStyle: color,
opacity: 1
},
// 与空气的摩擦力,该值越高,物体碰撞后在空间中移动时减速得越快
frictionAir: 0.03,
});
}
/** @name 在一定范围内,生成随机数 **/
function randomNumber(min, max) {
return Math.random() * (max - min) + min;
}
创建小球的API方法还支持另外两个参数,能帮我们填充小球的颜色、透明度等等功能,具体可以参考文档说明。
Matter.Bodies.circle(x, y, radius, [options], [maxSides])
参数 options 的详细信息:传送门
效果:
现在咱们有了小球,接下来就让它们在页面滚动的时候,也跟着运动起来,让它们去相互碰撞。😗
来看代码:
// ...
window.addEventListener('scroll', scrollThrottled);
// 垂直方向滚动的距离
let initPageYOffset = window.pageYOffset;
let timer = null;
/** @name 滚动监听进行节流 **/
function scrollThrottled() {
if (!timer) timer = setTimeout(handleScroll, 100);
}
/** @name 滚动处理 **/
function handleScroll() {
timer = null;
// 根据滚动距离计算小球运动距离
let delta = (initPageYOffset - window.pageYOffset) * 0.025;
balls.forEach(ball => {
// 重新设置小球的线速度
Matter.Body.setVelocity(ball, {
x: ball.velocity.x + delta * randomNumber(-0.5, 0.5),
y: ball.velocity.y + delta * randomNumber(0.5, 1.5)
});
});
initPageYOffset = window.pageYOffset;
}
上面,我们通过计算页面滚动的距离,为每个小球添加了适当的垂直速度,同时引入了一些随机性,让小球的运动看起来更加自然。此外,我们也为小球增加了一点点水平速度,进一步增强了它们的动态运动效果。
而给小球增加速度是使用了 setVelocity 方法,它的参数情况如下:
Matter.Body.setVelocity(body, velocity)
参数 velocity 的详细信息:传送门
现在小球能跟着页面滚动而运动了,只是仅仅只有十几个小球,滚动一下就没了?😓
这会就要使用到我们上面提到的第二个包:matter-wrap
它的作用是"在物体穿过边界时,物体将出现在边界的另一侧,同时保持其速度。"
简单来说,它能帮我们解决上面的问题,让我们的小球无穷无尽的出现。
且看:
<script>
// 引入插件
Matter.use('matter-wrap');
window.addEventListener('DOMContentLoaded', () => {
// ...
/** @name 生成小球 **/
function createBall(width, height) {
// ...
// 生成一个小球
return Matter.Bodies.circle(x, y, radius, {
render: {
fillStyle: color,
opacity: 1
},
frictionAir: 0.03,
// 使用物体使用matter-wrap
plugin: {
wrap: {
min: { x: 0, y: 0 },
max: { x: width, y: height }
}
}
});
}
// ...
});
使用起来很简单,就是配置到每个物体(小球)身上,让它们都使用 matter-wrap 规定边界的情况。
配置后,就能做到和开头的案例一样的效果啦。👻
当然,你也可以通过去修改 createBall 方法创建各种各样的图形,反正玩起来效果都挺不错,Interesting!
至此,本篇文章就写完啦,撒花撒花。
希望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+评论=你会了,收藏=你精通了。