Cocos 粒子特效实战:2D/3D 选型、火焰与魔法光晕、移动端性能避坑
【免费下载链接】cocos-engineCocos simplifies game creation and distribution with Cocos Creator, a free, open-source, cross-platform game engine. Empowering millions of developers to create high-performance, engaging 2D/3D games and instant web entertainment.项目地址: https://gitcode.com/GitHub_Trending/co/cocos-engine
想让角色周身滚一圈魔法光晕,或者在地面烧出一簇往上窜的火焰?这类"活的"视觉,靠几张图根本做不出来,得靠引擎的粒子系统。Cocos Creator 内置了2D和3D两套粒子组件:前者轻快、适合 UI 和平面特效,后者带发射器形状、三维大小和噪声模块,适合空间感强的场景。这篇直接给结论:怎么选、关键参数怎么填、移动端为什么会卡。你照着跑一遍,再回头调参数。
先定方向:2D 还是 3D 粒子
两套组件在同一个仓库里分得很开:2D 在 cocos/particle-2d/,3D 在 cocos/particle/。别被名字唬住,核心差异就四点,看完这张表你基本能拍板:
| 对比维度 | 2D 粒子(ParticleSystem2D) | 3D 粒子(ParticleSystem) |
|---|---|---|
| 控制维度 | 平面,angle/speed/重力 + 切向、径向加速度 | 三维空间,startSizeX/Y/Z、startSpeed、发射器形状 |
| 发射器 | 只有GRAVITY/RADIUS两种模式 | shapeModule提供 Box/Circle/Cone/Sphere/Hemisphere |
| 渲染 | 走 UI 批次渲染,天然省 | 支持 CPU 模拟或 GPU(顶点着色器)模拟 |
| 高级模块 | 无噪声、无轨迹 | 噪声、轨迹、限制速度、随寿命变色等 |
| 性能开销 | 极低,可大量铺 | 较高,GPU 模式能压下来 |
| 适用场景 | 火焰、烟雾、雨雪、UI 光效 | 环绕光晕、爆炸、空间流体感 |
经验一句话:平面特效选 2D,要"包围感"和空间运动再上 3D。下面两个案例各演示一套。
案例一:用 2D 粒子做一簇上升火焰
思路:火焰的"灵魂"是往上冲、边冲边卷、颜色从亮橙烫到暗红最后淡没。2D 的重力模式正好能表达"冲 + 卷"——初速决定冲多快,切向力决定卷多狠。
先看发射节奏,这几个数直接决定火焰"旺不旺":
import { Node, ParticleSystem2D, Vec2, Color } from 'cc'; const ps = this.node.addComponent(ParticleSystem2D); ps.custom = true; // 走自定义参数,而不是读 ParticleAsset 配置 ps.totalParticles = 200; // 上限,防超发 ps.emissionRate = 60; // 每秒放 60 个 ps.duration = -1; // -1 = 一直发射 ps.life = 1.5; // 单粒子活 1.5 秒 ps.lifeVar = 0.5; // ±0.5 秒抖动,避免"齐步走"duration = -1是持续发射的约定值;lifeVar让每个粒子寿命略有差异,火焰才不会一抽一抽。
关键参数:切向力是火焰"卷起来"的来源,径向力控制扩散收拢。把重力先关掉,只靠初速往上走:
ps.emitterMode = ParticleSystem2D.EmitterMode.GRAVITY; // 重力模式 ps.gravity = new Vec2(0, 0); // 先不上重力,纯靠速度向上 ps.speed = 180; // 初速:冲多快 ps.angle = 90; // 朝正上方 ps.tangentialAccel = 80; // 切向力:做出翻滚感 ps.radialAccel = 0; // 径向力:暂时不收拢颜色是火焰的命。从亮橙起步,endColor的透明度打到 0,粒子飞着飞着就"烧没了":
ps.startColor = new Color(255, 180, 40, 255); // 亮橙 ps.startColorVar = new Color(40, 40, 0, 0); // 起点色随机抖动 ps.endColor = new Color(200, 40, 0, 0); // 暗红且 alpha=0 → 淡出这里有个坑:endSize默认是0,不写就等于"越飞越小"。火焰通常出生小、长大再收尾,记得显式给:
ps.startSize = 24; ps.endSize = 60; // 不写这行,粒子会越升越小 ps.positionType = ParticleSystem2D.PositionType.FREE; // 自由模式,留在原地升腾纹理直接用引擎自带的Default-Particle.png(editor/assets/Default-Particle.png)就能出效果。💡 想让火焰"越叠越亮",混合模式不是组件上的下拉框,而是由它绑定的材质决定的——在粒子材质的 Blend 里选加法混合,重叠的粒子会互相提亮,这才像火。
案例二:用 3D 粒子做环绕魔法光晕
思路:光晕要"包围"角色,所以发射器得是个球,粒子从球体表面一圈一圈往外发,再叠加一点噪声让它自然飘。3D 组件默认参数已经给了合理起点(容量 100、生命周期 5 秒、初速 5),你要做的是覆盖。
基础量先定下来:
import { ParticleSystem, ParticleSpace, ParticleShapeType, ParticleEmitLocation } from 'cc'; const ps = this.node.addComponent(ParticleSystem); ps.capacity = 300; // 最大粒子数 ps.duration = 5; ps.loop = true; // 循环播放 ps.simulationSpace = ParticleSpace.Local; // 跟随角色,不钉死在世界 ps.startLifetime.constant = 2; // 每个粒子活 2 秒simulationSpace选Local很关键——光晕要跟着角色走,不能角色一动光晕留在原地。
发射器用球体,注意 3D 里 shape 模块的开关字段名是enable(不是enabled):
const shape = ps.shapeModule; shape.enable = true; // 打开发射器模块 shape.shapeType = ParticleShapeType.Sphere; // 球体发射 shape.emitFrom = ParticleEmitLocation.Volume; // 从球体内部发 shape.radius = 1.5; // 球半径三维大小要先打开startSize3D,X/Y/Z才会分别生效,否则只有startSizeX起作用:
ps.startSize3D = true; ps.startSizeX.constant = 0.5; ps.startSizeY.constant = 0.5; ps.startSizeZ.constant = 0.5;颜色随寿命渐变走的是colorOverLifetimeModule,内部用一条色带描述"从出生到死亡颜色怎么变"。编辑器里把色带从紫拉到青再拉到黄,就能出彩虹光晕,比硬编码几个颜色点省事。
加噪声让它"活"起来:3D 的噪声模块靠strengthX/Y/Z三个分量控制扰动幅度(注意它只在 CPU 模拟下生效,别开在 GPU 模式上):
const noise = ps.noiseModule; noise.strengthX = 0.5; noise.strengthY = 0.5; noise.strengthZ = 0.5;渲染交给 GPU:把模拟挪到顶点着色器,CPU 几乎不占。配合面向摄像机的广告牌模式,最通用也最省:
ps.renderer.useGPU = true; // GPU 粒子 ps.renderer.renderMode = ParticleRenderMode.Billboard; // 始终面向镜头⚠️ 切到 GPU 之前先看一眼设备能力:引擎会在设备不支持顶点纹理或浮点纹理时回退到 CPU,日志里会提示,移动端务必真机验证。
调参速查表
两套系统高频参数的"作用 + 怎么取值",调的时候对照着改:
2D 粒子(ParticleSystem2D)
| 参数 | 作用 | 取值建议 |
|---|---|---|
totalParticles | 粒子数量上限 | 移动端 ≤300 |
emissionRate | 每秒发射数 | 配合life控活跃量 |
duration | 发射器存活时间 | -1持续发射 |
life/lifeVar | 生命周期及抖动 | 主值 1~2 秒,抖动取 1/3 |
startColor/endColor | 起止颜色 | 末色 alpha 设 0 做淡出 |
startSize/endSize | 起止大小 | endSize默认 0,注意别漏 |
tangentialAccel/radialAccel | 切向 / 径向加速度(仅重力模式) | 正负号控制"卷"与"收拢" |
positionType | 粒子跟随方式 | 火焰用FREE,跟角色用GROUPED |
3D 粒子(ParticleSystem)
| 参数 | 作用 | 取值建议 |
|---|---|---|
capacity | 最大粒子数 | 移动端 ≤300 |
loop/duration | 是否循环 / 时长 | 循环特效loop=true |
simulationSpace | 模拟坐标系 | 跟角色用Local |
startLifetime.constant | 单粒子寿命 | 光晕约 2 秒 |
shapeModule.enable/shapeType | 发射器开关 / 形状 | 环绕用Sphere+Volume |
startSize3D+startSizeX/Y/Z | 三维大小 | 打开startSize3D才分轴 |
noiseModule.strengthX/Y/Z | 噪声扰动(仅 CPU) | 0.3~0.6 起步 |
renderer.useGPU | 是否 GPU 模拟 | 量大优先开,验证能力 |
移动端性能避坑清单
三条最常见的坑,按"问题 → 原因 → 解法"拆开:
- 卡顿:粒子太多叠加 GPU 过绘制 → 透明粒子互相覆盖,填充率爆表 → 单系统控制在 300 内,纹理别超过 256×256,能关的噪声/轨迹先关。
- 帧率骤降且 CPU 高:大数量粒子却用了 CPU 模拟 → 每个粒子都在 JS 里逐帧算 → 开
renderer.useGPU = true,把模拟甩给顶点着色器(前提:设备支持顶点/浮点纹理)。 - 内存涨、节点残留:播放完的节点没销毁,或被父节点引用住 → 2D 开
autoRemoveOnFinish,3D 用完手动destroy;同类特效共享同一份材质和资源,别每帧new。 - 切到 GPU 后效果消失/回退:设备不支持顶点纹理或浮点纹理 → 引擎静默回退 CPU 并打日志 → 真机验证,别只在桌面端看。
进阶玩法与收尾
两个能力点到为止,需要时再深入:
- 轨迹(Trail):3D 的
trailModule能给粒子拖一条尾迹,做流光、拖尾很合适——但它只在 CPU 模拟下可用,和 GPU 二选一。 - 纹理动画(TextureAnimation):
textureAnimationModule让粒子在生命周期里翻帧,做爆炸、魔法爆开这种"逐帧变化"的效果,比单张静态图生动得多。 - 限制速度 / 力场:
limitVelocityOvertimeModule、forceOvertimeModule能控制粒子收拢、加速,都是 CPU 侧能力。
2D 轻、3D 强、GPU 省——三件事记住就够用了。建议你把上面的火焰和光晕各跑一遍,先在真机上量一次帧率,再回头对着速查表调参数,手感很快就有了。
【免费下载链接】cocos-engineCocos simplifies game creation and distribution with Cocos Creator, a free, open-source, cross-platform game engine. Empowering millions of developers to create high-performance, engaging 2D/3D games and instant web entertainment.项目地址: https://gitcode.com/GitHub_Trending/co/cocos-engine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考