Canvas黑洞效果核心是用牛顿引力公式模拟粒子运动:每帧计算指向黑洞的归一化方向向量,加速度按距离平方反比衰减(ax=dx/dist/(dist×0.01)),再累加至速度并更新位置;粒子近黑洞时变亮后消失,模拟吸积盘发光与事件视界不可见性。

Canvas 实现黑洞效果,核心不是“画个黑圆”,而是用数学模拟引力场 + 粒子响应 + 视觉欺骗。直接套用渐变或阴影只能糊弄一眼,真要粒子绕转、加速坠入、边缘扭曲,得靠 requestAnimationFrame 持续更新位置和状态,且关键参数(如引力衰减指数、粒子生命周期)稍一越界,动画就卡顿或飞出画布。
怎么让粒子真实“被吸进去”而不是直线撞向中心
靠牛顿万有引力公式简化版:force = G * mass / distance²,但 Canvas 里不用单位,只用比例关系。实际做时,粒子每帧的加速度方向必须实时指向黑洞中心,大小按距离平方反比衰减——否则会变成匀速冲向中心,失去旋转感和“悬停再坠入”的临界态。
- 黑洞坐标设为
blackHole.x、blackHole.y,粒子当前坐标是p.x、p.y - 先算偏移:
dx = blackHole.x - p.x,dy = blackHole.y - p.y - 再算距离:
dist = Math.sqrt(dx*dx + dy*dy),注意加0.1防除零 - 加速度分量:
ax = dx / dist / (dist * 0.01),ay = dy / dist / (dist * 0.01)(0.01 是可调引力系数) - 再把
ax/ay累加到p.vx/p.vy,最后更新位置:p.x += p.vx,p.y += p.vy
漏掉归一化方向(即除以 dist)会导致远距离粒子加速度爆炸;不加距离平方衰减,近处粒子又会瞬间消失。
为什么粒子靠近黑洞后突然“变亮又消失”
这是视觉反馈的关键设计点,不是 bug。真实黑洞吸积盘高温发光,但事件视界内光无法逃逸——所以粒子在 dist 时,应逐步增大透明度(<code>ctx.globalAlpha),同时轻微放大尺寸(模拟引力透镜拉伸),并在 dist 时从数组中 <code>splice 删除或重置。
- 别用
ctx.clearRect清全屏来“擦掉”粒子,那会闪屏;用半透明背景色覆盖:ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'+ctx.fillRect(0, 0, width, height) - 粒子透明度建议映射为:
alpha = Math.min(1, dist / (BLACK_HOLE_RADIUS * 3)),这样越近越透明,自然“隐入” - 重置粒子时,不要随机扔到画布边缘——统一放在黑洞外圈(如
radius = BLACK_HOLE_RADIUS * (8 + Math.random() * 5)),避免刚重生就又被吸走
鼠标跟随黑洞时,为什么粒子轨迹会乱跳
因为黑洞坐标突变,而粒子速度没做平滑过渡。直接赋值 blackHole.x = e.clientX 后,所有粒子下一帧的 dx/dy 全部重算,导致加速度方向剧烈抖动。
- 解决方案:给黑洞加“惯性”,用插值缓动:
blackHole.x += (targetX - blackHole.x) * 0.08,blackHole.y += (targetY - blackHole.y) * 0.08 - 0.08 是阻尼系数,太小响应迟钝,太大仍会抖;建议范围 0.04–0.12
- 粒子自身的
vx/vy不需要改,它们会自动跟随新引力场,但初始抖动靠黑洞缓动就能压住
真正难调的是粒子密度与帧率的平衡:1000 个粒子在低端机上 requestAnimationFrame 很容易跌破 30fps;删到 300 个又显空洞。不如用分层策略——近处高精度计算,远处只做线性逼近,或者用 Uint8Array 批量处理位置,这些细节比“怎么画黑洞”更决定最终效果是否可用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











