
本文共 4248 字,大约阅读时间需要 14 分钟。
实现粒子系统网格动态效果
最近哈,这个粒子系统网格的效果真是太酷了!当我看到它动起来的时候,脑子里不停地想着该怎么实现它。其实这不是特别难,但得一步步来,仔细思考每一个细节。
首先,我们来分析一下这个效果到底有哪些要点。这个效果主要是由大量粒子组成的网格,每个粒子可以看作是一个微小的点。当你在屏幕上移动鼠标的时候,这些粒子会跟随鼠标移动,而当它们移动到边缘时,会反弹回来。连接粒子的线条也会随着粒子的距离而变化,距离近的粒子之间的连接线比较粗而且透明度低,距离远的则相反。
开始编码
首先是HTML部分,我简单放了一个 canvas 标签,并设置了它的样式,使其填充全屏。
为了让所有元素不留空隙,我还设置了一条全局样式:
*{ margin: 0; padding: 0;}
JavaScript部分
接下来到了核心代码部分。首先我们要获取到 canvas 和绘图上下文:
var canvasEl = document.getElementById('canvas');var ctx = canvasEl.getContext('2d');var mousePos = [0, 0];var easingFactor = 5.0;var backgroundColor = '#000';var nodeColor = '#fff';var edgeColor = '#fff';
然后我们声明了两个变量来存储“星星”和边:
var nodes = [];var edges = [];
为了确保画布在窗口大小发生变化时能够重新绘制并调整分辨率,我们设置了一个 resize 事件监听器:
window.onresize = function(){ canvasEl.width = document.body.clientWidth; canvasEl.height = canvasEl.clientHeight; if (nodes.length === 0) { constructNodes(); } render();};window.onresize();
第一次大小变化后,我们会调用 constructNodes()
来构建所有节点。这是个重要的函数,因为它随机创建了一些点,并将它们的信息存储在一个字典对象中:
function constructNodes(){ for (var i = 0; i < 100; i++) { var node = { drivenByMouse: i === 0, x: Math.random() * canvasEl.width, y: Math.random() * canvasEl.height, vx: Math.random() * 1 - 0.5, vy: Math.random() * 1 - 0.5, radius: Math.random() > 0.9 ? 3 + Math.random() * 3 : 1 + Math.random() * 3 }; nodes.push(node); } nodes.forEach(function(e) { nodes.forEach(function(e2) { if (e !== e2) { var edge = { from: e, to: e2 }; addEdge(edge); } }); });}
接着我们需要构建节点与节点之间的边,但由于双重循环会导致重复添加边的问题,我们引入了一个 addEdge
函数来避免重复:
function addEdge(edge){ var ignore = false; edges.forEach(function(e) { if (e.from === edge.from && e.to === edge.to) { ignore = true; return; } if (e.to === edge.from && e.from === edge.to) { ignore = true; return; } }); if (!ignore) { edges.push(edge); }}
粒子系统核心逻辑
接下来是让粒子系统动起来的关键部分。我们定义了一个 step()
函数,它会更新每个粒子的位置:
function step(){ nodes.forEach(function(e) { if (e.drivenByMouse) { return; } e.x += e.vx; e.y += e.vy; function clamp(min, max, value) { if (value > max) { return max; } else if (value < min) { return min; } else { return value; } } if (e.x <= 0 || e.x >= canvasEl.width) { e.vx *= -1; e.x = clamp(0, canvasEl.width, e.x); } if (e.y <= 0 || e.y >= canvasEl.height) { e.vy *= -1; e.y = clamp(0, canvasEl.height, e.y); } }); adjustNodeDrivenByMouse(); render(); window.requestAnimationFrame(step);}
我们还引入了 adjustNodeDrivenByMouse
函数来让特定的节点(下面一个星星)跟随鼠标移动:
function adjustNodeDrivenByMouse(){ nodes[0].x += (mousePos[0] - nodes[0].x) / easingFactor; nodes[0].y += (mousePos[1] - nodes[0].y) / easingFactor;}
最终,我们需要绘制粒子和连接线:
function lengthOfEdge(edge){ return Math.sqrt(Math.pow((edge.from.x - edge.to.x), 2) + Math.pow((edge.from.y - edge.to.y), 2));}function render(){ ctx.fillStyle = backgroundColor; ctx.fillRect(0, 0, canvasEl.width, canvasEl.height); edges.forEach(function(e) { var l = lengthOfEdge(e); var threshold = canvasEl.width / 8; if (l > threshold) { return; } ctx.strokeStyle = edgeColor; ctx.lineWidth = (1.0 - l / threshold) * 2.5; ctx.globalAlpha = 1.0 - l / threshold; ctx.beginPath(); ctx.moveTo(e.from.x, e.from.y); ctx.lineTo(e.to.x, e.to.y); ctx.stroke(); }); ctx.globalAlpha = 1.0; nodes.forEach(function(e) { if (e.drivenByMouse) { return; } ctx.fillStyle = nodeColor; ctx.beginPath(); ctx.arc(e.x, e.y, e.radius, 0, 2 * Math.PI); ctx.fill(); });}
总结
通过以上代码,我们成功地将粒子系统网格效果实现了。这个系统包括了粒子的运动逻辑、边缘碰撞检测以及鼠标跟随功能。通过合理设置参数和优化绘图效果,我们能够创造出一种非常酷炫的网格动态效果。如果你对粒子系统感兴趣,这篇文章提供了一种很好的编程思路和实践经验。
发表评论
最新留言
关于作者
