Pixi.js 游戏开发教程 / Pixi.js 粒子系统(@pixi/particle-emitter)
15. 粒子系统(@pixi/particle-emitter)
概述
粒子系统用于创建火焰、爆炸、烟雾、星光等视觉效果。@pixi/particle-emitter 是 Pixi.js 生态中最流行的粒子库,支持丰富的配置选项和高性能渲染。
安装与基本使用
npm install @pixi/particle-emitter
import { Application, Container } from 'pixi.js';
import { Emitter } from '@pixi/particle-emitter';
const app = new Application();
await app.init({ width: 800, height: 600 });
const particleContainer = new Container();
app.stage.addChild(particleContainer);
// 基础发射器配置
const emitter = new Emitter(particleContainer, {
lifetime: { min: 0.5, max: 1.5 },
frequency: 0.01, // 每 0.01 秒发射一个粒子
emitterLifetime: -1, // -1 = 永久发射
maxParticles: 500,
pos: { x: 400, y: 300 },
behaviors: [
{
type: 'alpha',
config: {
alpha: {
list: [
{ value: 1, time: 0 },
{ value: 0, time: 1 },
],
},
},
},
{
type: 'scale',
config: {
scale: {
list: [
{ value: 0.5, time: 0 },
{ value: 0.1, time: 1 },
],
},
},
},
{
type: 'moveSpeed',
config: {
speed: {
list: [
{ value: 100, time: 0 },
{ value: 20, time: 1 },
],
},
},
},
{
type: 'color',
config: {
color: {
list: [
{ value: 'ff6600', time: 0 },
{ value: 'ff0000', time: 0.5 },
{ value: '333333', time: 1 },
],
},
},
},
{
type: 'textureSingle',
config: {
texture: '/image/particle.png',
},
},
],
});
// 更新循环
app.ticker.add((ticker) => {
emitter.update(ticker.deltaMS * 0.001);
});
发射器配置详解
发射类型
| 类型 | 配置 | 说明 |
|---|---|---|
| 点发射 | spawnType: 'point' | 从单点发射(默认) |
| 线发射 | spawnType: 'line' | 沿线段发射 |
| 圆发射 | spawnType: 'circle' | 从圆周发射 |
| 矩形发射 | spawnType: 'rect' | 从矩形区域发射 |
| 环形发射 | spawnType: 'ring' | 从环形区域发射 |
// 矩形区域发射(如篝火上方)
{
type: 'spawnShape',
config: {
type: 'rect',
data: { x: -20, y: -5, w: 40, h: 10 },
},
}
// 环形发射(如魔法光环)
{
type: 'spawnShape',
config: {
type: 'ring',
data: {
x: 0, y: 0,
minRadius: 40,
maxRadius: 50,
},
},
}
速度与方向
{
type: 'moveSpeed',
config: {
speed: {
list: [
{ value: 200, time: 0 },
{ value: 0, time: 1 },
],
},
minMult: 0.5, // 速度随机倍率最小值
},
},
{
type: 'moveAcceleration',
config: {
accel: { x: 0, y: 500 }, // 重力下坠
minMult: 1,
},
},
{
type: 'rotation',
config: {
minStart: 0,
maxStart: 360,
minEnd: 0,
maxEnd: 360,
},
},
生命周期、颜色、缩放
// 生命周期:每个粒子存活时间
{ lifetime: { min: 0.3, max: 1.0 } }
// 颜色渐变
{
type: 'color',
config: {
color: {
list: [
{ value: 'ffffff', time: 0 },
{ value: '00aaff', time: 0.5 },
{ value: '000033', time: 1 },
],
},
},
}
// 缩放渐变
{
type: 'scale',
config: {
scale: {
list: [
{ value: 1.0, time: 0 },
{ value: 0.0, time: 1 },
],
},
minMult: 0.5,
},
}
粒子池(复用)
@pixi/particle-emitter 内部使用粒子池,但你需要注意纹理管理:
// 共享纹理提高性能
import { Texture } from 'pixi.js';
const sharedParticleTex = Texture.from('/image/particle.png');
// 多个发射器共享同一纹理
const fireEmitter = new Emitter(container, {
// ...
behaviors: [
{ type: 'textureSingle', config: { texture: sharedParticleTex } },
],
});
const smokeEmitter = new Emitter(container, {
// ...
behaviors: [
{ type: 'textureSingle', config: { texture: sharedParticleTex } },
],
});
💡 提示:所有粒子使用相同的白色圆形纹理(白圆),通过颜色和缩放变化来表现不同效果,这样只需加载一张纹理。
火焰效果
const fireConfig = {
lifetime: { min: 0.3, max: 0.8 },
frequency: 0.005,
maxParticles: 300,
pos: { x: 0, y: 0 },
behaviors: [
{
type: 'alpha',
config: {
alpha: {
list: [
{ value: 0.8, time: 0 },
{ value: 0.0, time: 1 },
],
},
},
},
{
type: 'scale',
config: {
scale: {
list: [
{ value: 0.8, time: 0 },
{ value: 0.2, time: 1 },
],
},
},
},
{
type: 'color',
config: {
color: {
list: [
{ value: 'ffff00', time: 0 },
{ value: 'ff6600', time: 0.3 },
{ value: 'cc0000', time: 0.7 },
{ value: '333333', time: 1 },
],
},
},
},
{
type: 'moveSpeed',
config: {
speed: {
list: [
{ value: 80, time: 0 },
{ value: 20, time: 1 },
],
},
minMult: 0.5,
},
},
{
type: 'rotation',
config: { minStart: -90, maxStart: -90, minEnd: -90, maxEnd: -90 },
},
{
type: 'textureSingle',
config: { texture: '/image/particle.png' },
},
{
type: 'spawnShape',
config: {
type: 'rect',
data: { x: -15, y: -5, w: 30, h: 10 },
},
},
],
};
爆炸效果
function createExplosion(container, x, y) {
const explosion = new Emitter(container, {
lifetime: { min: 0.2, max: 0.6 },
frequency: 0.001, // 快速发射
emitterLifetime: 0.1, // 只发射 0.1 秒
maxParticles: 100,
pos: { x, y },
behaviors: [
{
type: 'alpha',
config: {
alpha: {
list: [
{ value: 1.0, time: 0 },
{ value: 0.0, time: 1 },
],
},
},
},
{
type: 'scale',
config: {
scale: {
list: [
{ value: 1.5, time: 0 },
{ value: 0.0, time: 1 },
],
},
},
},
{
type: 'moveSpeed',
config: {
speed: {
list: [
{ value: 400, time: 0 },
{ value: 0, time: 1 },
],
},
},
},
{
type: 'color',
config: {
color: {
list: [
{ value: 'ffffff', time: 0 },
{ value: 'ffaa00', time: 0.2 },
{ value: 'ff4400', time: 0.5 },
{ value: '444444', time: 1 },
],
},
},
},
{
type: 'textureSingle',
config: { texture: '/image/particle.png' },
},
],
});
// 发射完成后清理
setTimeout(() => {
explosion.destroy();
}, 2000);
return explosion;
}
烟雾效果
const smokeConfig = {
lifetime: { min: 2.0, max: 4.0 },
frequency: 0.05,
maxParticles: 100,
behaviors: [
{
type: 'alpha',
config: {
alpha: {
list: [
{ value: 0.0, time: 0 },
{ value: 0.3, time: 0.2 },
{ value: 0.0, time: 1 },
],
},
},
},
{
type: 'scale',
config: {
scale: {
list: [
{ value: 0.3, time: 0 },
{ value: 2.0, time: 1 },
],
},
},
},
{
type: 'moveSpeed',
config: {
speed: {
list: [
{ value: 30, time: 0 },
{ value: 10, time: 1 },
],
},
},
},
{
type: 'moveAcceleration',
config: {
accel: { x: 10, y: -20 }, // 向上飘散
},
},
{
type: 'textureSingle',
config: { texture: '/image/smoke.png' },
},
],
};
粒子与游戏事件联动
class ParticleEffectsManager {
private container: Container;
private emitters: Emitter[] = [];
constructor(parent: Container) {
this.container = new Container();
parent.addChild(this.container);
}
// 拾取物品闪光
pickupEffect(x: number, y: number, color: string) {
const emitter = new Emitter(this.container, {
lifetime: { min: 0.2, max: 0.5 },
frequency: 0.001,
emitterLifetime: 0.05,
maxParticles: 30,
pos: { x, y },
behaviors: [
{ type: 'alpha', config: { alpha: { list: [
{ value: 1, time: 0 }, { value: 0, time: 1 },
]}}},
{ type: 'scale', config: { scale: { list: [
{ value: 0.5, time: 0 }, { value: 0, time: 1 },
]}}},
{ type: 'moveSpeed', config: { speed: { list: [
{ value: 150, time: 0 }, { value: 0, time: 1 },
]}}},
{ type: 'color', config: { color: { list: [
{ value: color, time: 0 }, { value: 'ffffff', time: 1 },
]}}},
{ type: 'textureSingle', config: { texture: '/image/spark.png' } },
],
});
this.scheduleEmitterCleanup(emitter);
}
// 受伤闪红
damageEffect(x: number, y: number) {
this.pickupEffect(x, y, 'ff0000');
}
update(dt: number) {
for (const emitter of this.emitters) {
emitter.update(dt);
}
}
private scheduleEmitterCleanup(emitter: Emitter) {
this.emitters.push(emitter);
setTimeout(() => {
emitter.destroy();
this.emitters = this.emitters.filter(e => e !== emitter);
}, 3000);
}
}
GPU 粒子性能
| 优化手段 | 说明 |
|---|---|
使用 ParticleContainer | Pixi.js 的专用粒子容器,性能更高 |
| 限制最大粒子数 | maxParticles 设合理上限 |
| 共享纹理 | 所有粒子使用同一纹理 |
| 降低发射频率 | frequency 不必太小 |
| 复用发射器 | 使用对象池而非频繁创建/销毁 |
import { ParticleContainer } from 'pixi.js';
// ParticleContainer 不支持 tint、滤镜等,但性能更好
const particles = new ParticleContainer(10000, {
scale: true,
position: true,
alpha: true,
rotation: true,
});
粒子编辑器工具
| 工具 | 说明 | 链接 |
|---|---|---|
| Pixi Particles Editor | 在线编辑器 | https://pixi-particles.clevercanyon.com |
| Particle Designer | 桌面工具 | GitHub 开源 |
| 手写 JSON | 最灵活 | 直接编写配置对象 |
💡 提示:推荐先用在线编辑器调参预览,导出 JSON 后在代码中使用。
自定义粒子行为
// 自定义行为:粒子颜色随速度变化
class SpeedColorBehavior {
constructor(particle) {
this.particle = particle;
}
init(firstInit) {
// 初始化时调用
}
update(particle) {
const speed = Math.sqrt(
particle.vx * particle.vx + particle.vy * particle.vy
);
const t = Math.min(1, speed / 300);
// 速度越快越红
particle.tint = lerpColor(0x00aaff, 0xff0000, t);
}
destroy() {}
}
function lerpColor(a, b, t) {
const ar = (a >> 16) & 0xff;
const ag = (a >> 8) & 0xff;
const ab = a & 0xff;
const br = (b >> 16) & 0xff;
const bg = (b >> 8) & 0xff;
const bb = b & 0xff;
const r = Math.round(ar + (br - ar) * t);
const g = Math.round(ag + (bg - ag) * t);
const bl = Math.round(ab + (bb - ab) * t);
return (r << 16) | (g << 8) | bl;
}