mcpField
P
phaser-particles

phaser-particles

github.com/yakoub-ai开发2969 次安装9 周前更新
代码仓库

关于 phaser-particles

phaser-particles 是为 Phaser 4 游戏开发者提供粒子效果构建与调优指导的技能,涵盖发射器、粒子行为和运行时检查。它还说明如何限制粒子数量并控制性能开销。

主要功能

  1. 01单次爆发与持续发射
  2. 02配置粒子运动和外观
  3. 03设置发射区域与消亡区域
  4. 04跟随移动中的游戏对象
  5. 05粒子数量与性能指导
  6. 06运行时验证粒子效果

适用场景

  1. 01添加受击火花或拾取爆发效果
  2. 02制作雨、烟雾或火焰效果
  3. 03避免屏幕外粒子持续占用资源
  4. 04在高负载下测试粒子数量

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yakoub-ai/phaser4-gamedev --skill phaser-particles

安装后在 Claude Code 中输入/phaser-particles确认已加载。

附带文件references/particle-recipes.md

详细介绍

Phaser 4 粒子

粒子能让游戏显得反应灵敏。一次命中触发三个火花,带来的扎实感是没有火花时的两倍,而所需工作量只是其他任何增强表现手法的一小部分。

它们也是导致 Phaser 游戏以 20fps 运行的最常见原因。


发射器

const emitter = this.add.particles(x, y, 'texture', config);

一次调用就能创建并添加一个发射器。它是一个普通游戏对象:具有深度、滚动因子和 alpha,也可以放入容器中。

下面是一份实用配置示例,包含所有重要字段:

const sparks = this.add.particles(0, 0, 'flare', {
  // Motion
  speed: { min: 50, max: 150 },      // px/sec; a range gives natural spread
  angle: { min: 0, max: 360 },       // degrees; direction of travel
  gravityY: 300,                     // px/sec² — falling embers, debris
  accelerationX: 0,

  // Appearance over life — {start, end} interpolates across the particle's lifespan
  scale: { start: 1, end: 0 },
  alpha: { start: 1, end: 0 },
  rotate: { start: 0, end: 360 },
  tint: [0xffaa00, 0xff2200],        // an array picks randomly per particle
  blendMode: 'ADD',                  // ADD for light: fire, magic, sparks

  // Timing
  lifespan: 600,                     // ms each particle lives
  frequency: 40,                     // ms between emissions; -1 = explode mode only
  quantity: 2,                       // particles per emission

  // Budget — always set this
  maxParticles: 100,

  emitting: false,                   // create dormant; start it deliberately
});

{ start, end } 是核心。 粒子效果要显得精心设计而不是随意喷射,关键在于 scale 和 alpha 在生命周期内逐渐缩小并淡出。粒子如果以完整尺寸突然消失,看起来就像个 bug。


单次发射还是持续发射

两种模式,混淆它们就会导致效果要么完全不出现,要么永不停止。

爆发式发射 — 爆炸、命中火花、拾取物弹出:

const burst = this.add.particles(0, 0, 'spark', {
  speed: { min: 100, max: 300 },
  lifespan: 400,
  scale: { start: 0.8, end: 0 },
  emitting: false,                    // dormant until told otherwise
});

burst.explode(20, x, y);              // 20 particles, right here, right now

持续发射 — 火炬、烟柱、雨:

const smoke = this.add.particles(x, y, 'smoke', {
  frequency: 100,
  quantity: 1,
  lifespan: 2000,
  emitting: true,
});

smoke.stop();      // stop emitting; existing particles live out their lifespan
smoke.start();
smoke.pause();     // freeze everything, including live particles
smoke.resume();

stop() 和 pause() 不同,而且区别一目了然:stop() 会让烟柱自然消散,pause() 则会让它悬停在半空中。

清理: 每次爆炸都创建一个发射器却从不销毁,会造成泄漏。可以创建一个发射器并重复调用 explode(),也可以在最后一个粒子消失后将其销毁:

// Reuse — the right default
this.hitSparks.explode(8, enemy.x, enemy.y);

// Or fire-and-forget, cleaned up properly
const e = this.add.particles(x, y, 'spark', { lifespan: 400, emitting: false });
e.explode(20);
this.time.delayedCall(500, () => e.destroy());

跟随移动对象

emitter.startFollow(player, 0, -10);   // offsetX, offsetY
emitter.stopFollow();

用它来代替在 update() 中设置发射器位置。startFollow 会在帧与帧之间追踪对象,因此快速移动的对象会留下连续轨迹,而不是在每帧的位置留下一团团断续的粒子。


区域

发射区域 — 粒子的生成位置:

// Along the edge of a shape: a ring, a magic circle
emitter.addEmitZone({
  type: 'edge',
  source: new Phaser.Geom.Circle(0, 0, 50),
  quantity: 32,
});

// Anywhere inside a shape: rain across the top of the screen
emitter.addEmitZone({
  type: 'random',
  source: new Phaser.Geom.Rectangle(0, 0, 800, 10),
});

死亡区域 — 粒子的销毁位置:

emitter.addDeathZone({
  type: 'onEnter',                                  // or 'onLeave'
  source: new Phaser.Geom.Rectangle(0, 400, 800, 200),
});

使用覆盖整个屏幕的矩形和 onLeave,就能避免屏幕外的粒子产生任何开销。

重力井 — 吸引或排斥:

emitter.createGravityWell({ x: 400, y: 300, power: 3, epsilon: 100, gravity: 100 });

漩涡、黑洞、将硬币吸过来的磁铁拾取物。


性能 — 发布前请阅读

粒子是导致 Phaser 游戏帧率骤降的最常见原因,而且通常在代码写完很久之后才会出现,因为只有在负载较高时才会暴露。

务必设置 maxParticles。 没有上限且 frequency 较短的发射器会不断分配粒子,直到耗尽帧预算。这是任何发射器配置中最有价值的一行。

maxParticles: 100,       // hard ceiling

估算数量:lifespan / frequency * quantity 就是稳定状态下的粒子数量。设置为 lifespan: 2000, frequency: 40, quantity: 2 时,一个发射器就有 100 个活动粒子——如果有十个这样的发射器,就有 1,000 个。

其他优化手段,按大致收益排序:

手段原因
缩短 lifespan在视觉密度不变的情况下减少活动粒子
在 onLeave 上使用死亡区域屏幕外粒子的开销与可见粒子完全相同
使用更少、更大的粒子20 个大火花比 200 个小火花更醒目,开销也低 10 倍
重用同一个发射器发射器频繁创建和销毁的开销比粒子本身还大
使用更小的纹理粒子纹理通常无需超过 32×32
在移动设备上避免使用 ADD加法混合会大量消耗填充率,而移动设备的瓶颈正是填充率
stopAfter发射 N 个粒子后自动停止 — 无需担心遗漏清理逻辑

移动设备预算: 整个游戏同时存在几百个粒子,而不是每个效果几百个。将桌面端的数量减半,并在真实设备上检查 — 参见 skills/phaser-mobile/references/device-profiles.md。

如果需要处理数千个相似精灵,粒子就不是合适的工具 — 请参见 skills/phaser-fx/references/renderer-and-shaders.md 中的 SpriteGPULayer。


粒子不显示的原因

按可能性从高到低排列:

症状原因
完全没有emitting: false,且从未调用 start() 或 explode()
完全没有纹理键不存在——检查加载器和试玩资源检查
完全没有frequency: -1(仅爆发模式),但没有调用 explode()
不可见发射器深度低于背景——emitter.setDepth(n)
不可见alpha: { start: 0 }——归零的是起始值,而不是结束值
出现一帧后消失lifespan 过短
位置错误发射器的 x/y 是世界坐标;在容器内时,它们是局部坐标
不跟随在 update() 中设置位置,而不是使用 startFollow()
帧率骤降没有设置 maxParticles

在运行时验证粒子

粒子错误完全可以通过类型检查——错误的纹理键仍是字符串,而从未启动的发射器也属于有效代码。验证它确实运行了:

// playtest/particles-check.mjs
export default [
  { name: 'hit sparks fire on damage', action: 'eval',
    code: `scene('GameScene').hitEnemy(scene('GameScene').enemies[0])` },
  { name: 'particles actually spawned', action: 'expect',
    expect: { expression: `scene('GameScene').hitSparks.getAliveParticleCount()`, atLeast: 1 } },

  { name: 'and they are capped', action: 'sample',
    expression: `scene('GameScene').hitSparks.getAliveParticleCount()`,
    duration: 3000, interval: 100,
    expect: { stat: 'max', atMost: 100 } },

  { name: 'frame rate survives the effect', action: 'sample',
    expression: `game.loop.actualFps`, duration: 3000, interval: 100,
    expect: { stat: 'min', atLeast: 50 } },
];

对存活粒子数的 max 断言,可以在玩家发现之前捕获未设上限的发射器。在游戏粒子负载最高时运行,而不是在空闲时运行。


其他资源

参考文件
  • references/particle-recipes.md — 游戏实际需要的效果的完整配置:爆炸、火焰、烟雾、雨、雪、火花、血液、魔法、灰尘、枪口闪光、五彩纸屑、轨迹——每种效果都说明了各项数值的设定理由。
相关内容
  • skills/phaser-fx/ — 滤镜和混合模式;ADD 粒子搭配泛光操作是标准的“魔法”效果
  • skills/phaser-analyze/references/performance-playbook.md — 粒子何时会影响帧率
  • skills/phaser-mobile/references/device-profiles.md — 移动端粒子预算

评论

支持 Markdown