tsParticles 粒子碰撞系统全解:collisions 选项、bounce/destroy/absorb 三种模式与 overlap 防重叠机制
2026/9/17 2:55:30 网站建设 项目流程

tsParticles 粒子碰撞系统全解:collisions 选项、bounce/destroy/absorb 三种模式与 overlap 防重叠机制

【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles

本文以 tsParticles 官方选项文档 Collisions.md 为主体,系统讲解particles.collisions配置如何控制粒子之间的碰撞行为。读完本文,你将掌握三种碰撞模式(bounce / destroy / absorb)的完整配置方式、overlap出生防重叠机制的默认值与行为边界,并能结合 interactions/particles/collisions 包中的源码理解碰撞检测、能量守恒修正与吸收计算的底层实现,从而把碰撞效果稳定地用到自己的粒子背景、街机风特效或"粒子吞噬"场景中。

1. 文档定位:collisions 选项控制什么

官方文档给出的定义非常直接:"Controls how particles interact when they intersect each other."particles.collisions负责控制粒子彼此相交时的交互方式。该选项由独立包@tsparticles/interaction-particles-collisions(见 package.json)提供,随 particles 全量 bundle 一同发布,在配置中通常写作:

{ "particles": { "collisions": { "enable": true, "mode": "bounce" } } }

1.1 属性总表(继承文档并补全源码默认值)

文档 Collisions.md 给出的基础属性如下,本文结合选项类 Collisions.ts 的源码补全了默认值和文档未列出的absorbmaxSpeed两个字段:

KeyTypeExample默认值(源码)Notes
enablebooleantrue/falsefalse启用粒子间碰撞处理
modestring"bounce"/"destroy"/"absorb""bounce"碰撞行为模式
bounceobject见 Bounce 文档复用引擎的ParticlesBounce选项反弹微调选项(如damping等)
overlapobject{ "enable": false, "retries": 5 }enable: true/retries: 0初始出生时的重叠处理
absorbobject{ "speed": 5 }speed: 2吸收速度,仅mode: "absorb"时生效
maxSpeednumber5050(RangeValue)参与碰撞的粒子最大速度上限

其中mode的合法取值由枚举 CollisionMode.ts 定义:

export enum CollisionMode { absorb = "absorb", bounce = "bounce", destroy = "destroy", }

2. 三种碰撞模式及其行为

2.1 文档定义的行为对照

Mode行为(文档原文归纳)源码入口
"bounce"粒子相互弹开,双方都保留Bounce.ts
"destroy"撞击后移除其中一个粒子Destroy.ts
"absorb"一方吸收另一方,产生增大体积/质量的效果Absorb.ts

2.2 文档的三段快速示例(完整继承)

基础弹跳碰撞:

{ "collisions": { "enable": true, "mode": "bounce" } }

街机风破坏性碰撞:

{ "collisions": { "enable": true, "mode": "destroy" } }

吸收碰撞:

{ "collisions": { "enable": true, "mode": "absorb" } }

2.3 碰撞检测与分发的底层实现

上述三种模式的判定并非各写一套检测逻辑,而是统一走一个入口。核心流程可以从源码中清晰读出:

  1. 网格加速查询:交互器 Collider.ts 在interact()中先用container.particles.grid.queryCircle(pos1, radius1 * 2)以当前粒子为圆心、两倍半径为查询半径,从空间网格中取出候选邻居,避免 O(n²) 全量两两比较——这正是文档"常见陷阱"中提到"高粒子数下开启碰撞开销较大"仍然可接受的底层原因。
  2. 逐对过滤:候选粒子对必须同时满足:双方collisions.enable均为true、双方mode相同、双方都未销毁且不在出生中(spawning)。值得注意的是p1.options.collisions.mode !== p2.options.collisions.mode时会直接跳过,即混合模式(一部分粒子 bounce、一部分 destroy)不会发生碰撞。
  3. 深度过滤Math.abs(Math.round(pos1.z) - Math.round(pos2.z)) > radius1 + radius2时跳过,粒子系统支持 z 轴伪深度,深度差超过两球半径之和的粒子对不参与碰撞。
  4. 距离判定getDistance(pos1, pos2) > radius1 + radius2时视为未相交,否则调用 ResolveCollision.ts 按mode分发到absorb/bounce/destroy三个函数。

2.4 bounce:带能量守恒修正与限速的弹性碰撞

bounce() 的实现比"单纯换速度方向"要讲究:

  • 先记录碰撞前两粒子的质量m1m2与速度,计算碰撞前总动能keBefore
  • 调用引擎的circleBounce(两圆弹性碰撞解算)交换速度;
  • 碰撞后重新计算动能keAfter,若keAfter相对keBefore出现漂移超过阈值(energyDriftThreshold = 1e-4),则用correctionFactor = sqrt(keBefore / keAfter)等比回缩双方速度——这是一个数值稳定化处理,防止浮点误差在多帧累积后让粒子"越弹越快";
  • 最后fixBounceSpeed对双方做限速:把粒子速度钳制到collisions.maxSpeed(默认 50,支持 RangeValue 区间取值)。这就是为什么配置里可以写"maxSpeed": { "min": 30, "max": 60 }

仓库内 collisionsBounce 示例配置 展示了一个完整可用的弹跳场景:80 个粒子、圆形 shape、opacity: 0.5size10~15、move.speed: 10collisions: { enable: true }(mode 缺省即 bounce),背景色#0d47a1,并叠加了push/grab/bubble/repulse交互模式。

2.5 destroy:先弹开、再移除较小一方

destroy() 的逻辑分两步:

  1. 若双方都不是unbreakable(不可破坏),则先执行一次bounce,让两粒子在消失前产生弹开的动量效果;
  2. 然后按半径规则移除一方:
    • 只有 p1 无半径(半径为 0)→ 销毁 p1;
    • 只有 p2 无半径 → 销毁 p2;
    • 双方都有半径 →销毁较小的一方p1.getRadius() >= p2.getRadius() ? p2 : p1)。

unbreakable是引擎粒子属性(见 Particle.ts 中"if true the particle won't destroy on collisions"的注释),可用于让某些粒子(如发射器生成的核心粒子)只弹不毁。

仓库内 collisionsDestroy 示例配置 是一个典型的"街机爆炸"方案:80 个彩色粒子,mode: "destroy",并且给每个粒子配置了destroy.mode: "split"——粒子被销毁时会分裂成 1~9 倍大小的子粒子(factor4~9),子粒子再关闭碰撞、带 1~2 秒的life自动消失;配合poisson: { enable: true }(泊松分布出生)与一个 100×100 的 emitter 持续补充粒子。这套组合拳解释了文档"常见陷阱"中"没有 emitter 的 destroy 模式会让粒子数迅速减少"的原因——示例正是靠 emitter 维持了粒子总量。

2.6 absorb:按 absorb.speed 逐帧吞噬

absorb() 的判定规则是:

  • 大半径粒子吸收小半径粒子(r1 >= r2时 p1 吸收 p2,反之亦然);
  • 每一帧的"吞噬量"shrinkAmount = clamp(absorbSpeed * delta.factor, 0, r2),即以absorb.speed(默认 2)为速率、按帧间时间因子delta.factor归一化,且单帧最多吞完对方半径,避免越界;
  • 体积增长按面积守恒计算:p1.size.value = sqrt(r1² + shrink²),即吸收的面积按圆面积累加再反推半径,视觉上表现为平滑长大而不是突增;
  • 被吸收者半径缩到<= pixelRatio(高 DPI 屏的像素比)时置 0 并destroy()

collisionsAbsorb 示例配置 将absorb.speed调到 5、move.speed压到 2,让粒子缓慢漂移时逐渐"吃"成一个大球,适合做生物/引力风格的背景。

3. overlap:出生防重叠选项

文档对overlap的定义是:"Controls how initial particles are placed when collisions are enabled."(控制启用碰撞时初始粒子的摆放方式)

KeyTypeExample默认值(源码)Notes
enablebooleantrue/falsetrue设为false时禁止出生重叠
retriesnumber10寻找无重叠出生点位的尝试次数上限

默认值来自 CollisionsOverlap.ts:enable = true(允许重叠)、retries = 0

3.1 防重叠的判定与失败行为

该功能由插件 OverlapPluginInstance.ts 实现,其checkParticlePosition()在粒子出生摆点时介入:

  • collisions.enablefalseoverlap.enabletrue时直接放行;
  • 否则遍历容器内全部粒子,只要存在getDistance(pos, p.position) < 新粒子半径 + 对方半径的重叠即判定该点位不可用,由引擎换一个点位重试;
  • 当重试次数tryCount超过retries上限时,抛出错误Particle is overlapping and can't be placed——即点位实在放不下时粒子会出生失败而不是强行重叠,这在密集场景下是文档提示"低 retries 值仍可能出现偶发重叠/失败"的机制来源。

3.2 文档示例:出生时禁止重叠

{ "collisions": { "enable": true, "overlap": { "enable": false, "retries": 5 } } }

含义:粒子出生时不允许与其他粒子重叠,最多尝试 5 次寻找合法点位;粒子较多、画布较小时建议适当调大retries,否则部分粒子可能因找不到位置而出生失败。

4. 文档"常见陷阱"逐条源码解读

文档列出了三条 Common pitfalls,均可在源码中找到对应依据:

  1. "开启碰撞且粒子数很高时,在大画布上开销可观"——碰撞检测走的是空间网格加速(grid.queryCircle,见 Collider.ts),把两两比较降为邻域查询;但每对相交粒子还要执行一次完整的物理求解(bounce 含动能计算与修正),粒子越密、画布越大,相交对数越多,帧成本自然上升。建议:控制number.valuedensity,必要时缩小粒子半径降低相交概率。
  2. "mode: 'destroy'不配合 emitter 会快速耗尽粒子"——destroy 每次碰撞必销毁一方(较小半径者),粒子总数单调下降;对照 collisionsDestroy.ts 示例,官方解法就是叠加emitterspoisson持续补员。
  3. "overlap.enable: falseretries偏低时,拥挤场景仍可能偶发重叠/异常"——从 OverlapPluginInstance.ts 可见超过 retries 后是抛错终止,拥挤画布中合法点位本就稀少,调大retries或放宽overlap.enable: true是更稳的取舍。

5. 实践建议与可参考的仓库资源

  • 只想做物理弹跳背景collisions: { enable: true }即可(mode 默认 bounce),参考 collisionsBounce.ts;想压低弹速上限时用maxSpeed(支持区间值)。
  • 做街机/爆炸类特效mode: "destroy"+destroy.mode: "split"+ emitter 补员 +poisson分布,参考 collisionsDestroy.ts;需要"主角"粒子不消失时用unbreakable
  • 做吞噬/成长类特效mode: "absorb"+absorb.speed(默认 2,示例中用 5)+ 低move.speed,参考 collisionsAbsorb.ts。
  • 调试提示:两种不同mode的粒子互不碰撞(Collider.ts 中 mode 不一致直接跳过);z 深度差超过两半径之和的粒子对同样不参与碰撞。

6. 相关文档与模块路径

  • 粒子根选项:Particles.md
  • 移动与反弹行为:Move.md、Bounce.md
  • 选项总入口:Options.md
  • 碰撞交互包源码:Collider.ts、ResolveCollision.ts、OverlapPluginInstance.ts
  • 官方内置示例配置:utils/configs/src/c/ 目录下的collisionsBounce.ts/collisionsDestroy.ts/collisionsAbsorb.ts

【免费下载链接】tsparticlestsParticles - Easily create highly customizable JavaScript particles effects, confetti explosions and fireworks animations and use them as animated backgrounds for your website. Ready to use components available for React.js, Vue.js (2.x and 3.x), Angular, Svelte, jQuery, Preact, Inferno, Solid, Riot and Web Components.项目地址: https://gitcode.com/GitHub_Trending/ts/tsparticles

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询