Skip to main content

particles

Use this skill when creating particle effects in Phaser 4. Covers ParticleEmitter, emission zones, death zones, particle properties, textures, gravity wells, and particle movement. Triggers on: particles, emitter, particle effect, explosion, fire, smoke.

Datos de origen

Repositorio
phaserjs/phaser
Última actividad en el origen
10 de abril de 2026 a las 12:38
Idioma detectado de SKILL.md
inglés
Estrellas
40.602
Forks
7182

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Explorador de archivos
2 archivos

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
particles
description
Use this skill when creating particle effects in Phaser 4. Covers ParticleEmitter, emission zones, death zones, particle properties, textures, gravity wells, and particle movement. Triggers on: particles, emitter, particle effect, explosion, fire, smoke.
# Particle System > Creating and controlling particle effects in Phaser 4 -- ParticleEmitter creation and configuration, emitter ops (value formats), gravity wells, emission and death zones, flow vs burst modes, following game objects, and particle callbacks. **Key source paths:** `src/gameobjects/particles/` **Related skills:** ../sprites-and-images/SKILL.md, ../loading-assets/SKILL.md ## Quick Start ```js // In a Scene's create() method: // Basic continuous emitter (flow mode) const emitter = this.add.particles(400, 300, 'flares', { frame: 'red', speed: 200, lifespan: 2000, scale: { start: 1, end: 0 }, alpha: { start: 1, end: 0 }, gravityY: 150 }); // One-shot burst (explode mode) const burst = this.add.particles(400, 300, 'flares', { frame: 'blue', speed: { min: 100, max: 300 }, lifespan: 1000, scale: { start: 0.5, end: 0 }, emitting: false // don't auto-start }); burst.explode(20); // emit 20 particles at once ``` ## Core Concepts ### ParticleEmitter `ParticleEmitter` extends `GameObject` and is added directly to the display list. It is both a game object (positionable, scalable, maskable) and the emitter itself. There is no separate manager -- `this.add.particles()` returns a `ParticleEmitter` instance. **Factory signature:** ```js this.add.particles(x, y, texture, config); // x, y: world position (both optional, default 0) // texture: string key or Texture instance // config: ParticleEmitterConfig object (optional, can call setConfig later) ``` **Mixins:** AlphaSingle, BlendMode, Depth, Lighting, Mask, RenderNodes, ScrollFactor, Texture, Transform, Visible. So you can call `setPosition()`, `setScale()`, `setDepth()`, `setBlendMode()`, `setMask()`, `setScrollFactor()`, etc. ### Particle A lightweight object owned by its emitter. Key properties: `x`, `y`, `velocityX/Y`, `accelerationX/Y`, `scaleX/Y`, `alpha`, `angle`, `rotation`, `tint`, `life` (total ms), `lifeCurrent` (remaining ms), `lifeT` (0-1 normalized), `bounce`, `delayCurrent`, `holdCurrent`. Particles are pooled internally -- you never create them manually. ### EmitterOp Value Formats Most config properties (speed, scale, alpha, angle, x, y, etc.) accept flexible value formats: ```js x: 400 // static value x: [100, 200, 300, 400] // random pick from array x: { min: 100, max: 700 } // random float in range x: { min: 100, max: 700, int: true } // random integer x: { random: [100, 700] } // random integer shorthand scale: { start: 0, end: 1 } // ease over lifetime (default linear) scale: { start: 0, end: 1, ease: 'bounce.out' } // custom ease scale: { start: 4, end: 0.5, random: true } // random start, ease to end x: { values: [50, 500, 200, 800], interpolation: 'catmull' } // interpolation x: { steps: 32, start: 0, end: 576 } // stepped sequential x: { steps: 32, start: 0, end: 576, yoyo: true } // stepped with yoyo x: { // custom callbacks onEmit: (particle, key, t, value) => value, onUpdate: (particle, key, t, value) => value } x: (particle, key, t, value) => value + 50 // emit-time callback shorthand ``` **Emit-only** (no onUpdate): `angle`, `delay`, `hold`, `lifespan`, `quantity`, `speedX`, `speedY`. **Emit + Update** (support start/end, onUpdate): `accelerationX/Y`, `alpha`, `bounce`, `maxVelocityX/Y`, `moveToX/Y`, `rotate`, `scaleX/Y`, `tint`, `x`, `y`. ### Flow vs Explode (Burst) **Flow mode** (`frequency >= 0`): emits `quantity` particles every `frequency` ms. Default is `frequency: 0` (every frame) with `emitting: true`. **Explode mode** (`frequency = -1`): emits a batch all at once, then stops. ```js emitter.flow(100, 5); // 5 particles every 100ms emitter.flow(100, 5, 50); // auto-stop after 50 total emitter.explode(30, 200, 400); // burst 30 at position emitter.explode(30); // burst at emitter position ``` ## Common Patterns ### Scale, Alpha, and Color Over Lifetime ```js // Scale and alpha with custom easing this.add.particles(400, 300, 'spark', { lifespan: 2000, speed: 100, scale: { start: 1, end: 0, ease: 'power2' }, alpha: { start: 1, end: 0, ease: 'cubic.in' } }); ``` ### Color Interpolation The `color` property interpolates through an array of colors over particle lifetime (overrides `tint`): ```js this.add.particles(400, 300, 'spark', { lifespan: 2000, speed: 100, scale: { start: 0.5, end: 0 }, color: [0xfacc22, 0xf89800, 0xf83600, 0x9f0404], colorEase: 'quad.out' }); ``` ### Tinting Particles ```js this.add.particles(400, 300, 'spark', { tint: 0xff0000 }); // static this.add.particles(400, 300, 'spark', { tint: { start: 0xffffff, end: 0xff0000 } }); // over lifetime ``` ### Gravity Wells A `GravityWell` applies inverse-square gravitational force, pulling (or repelling with negative `power`) particles toward a point. ```js const emitter = this.add.particles(400, 300, 'spark', { speed: 100, lifespan: 4000, scale: { start: 0.4, end: 0 }, quantity: 2 }); const well = emitter.createGravityWell({ x: 400, y: 300, power: 2, epsilon: 100, gravity: 50 }); // Update at runtime well.x = 300; well.power = -1; // negative = repel // Or create manually and add const well2 = new Phaser.GameObjects.Particles.GravityWell(500, 200, 3, 100, 50); emitter.addParticleProcessor(well2); emitter.removeParticleProcessor(well2); ``` ### Emission Zones (Random) A `RandomZone` spawns particles at random positions within a shape. The source must have a `getRandomPoint(point)` method -- all Phaser geometry classes (Circle, Ellipse, Rectangle, Triangle, Polygon, Line) support this, or provide a custom source: ```js // Using built-in geometry this.add.particles(400, 300, 'spark', { speed: 50, lifespan: 2000, emitZone: { type: 'random', source: new Phaser.Geom.Circle(0, 0, 100) } }); // Custom source object (any object with getRandomPoint) emitter.addEmitZone({ type: 'random', source: { getRandomPoint: (point) => { const a = Math.random() * Math.PI * 2; point.x = Math.cos(a) * 100; point.y = Math.sin(a) * 50; return point; } } }); ``` ### Emission Zones (Edge) An `EdgeZone` places particles sequentially along shape edges. The source must have a `getPoints(quantity, stepRate)` method. Curves, Paths, and all geometry shapes support this: ```js this.add.particles(400, 300, 'spark', { lifespan: 1500, speed: 20, emitZone: { type: 'edge', source: new Phaser.Geom.Circle(0, 0, 150), quantity: 48, // number of points on edge (use 0 with stepRate instead) yoyo: false, // reverse direction at ends seamless: true // remove duplicate endpoint } }); // Or add post-creation with any source that has getPoints emitter.addEmitZone({ type: 'edge', source: geom, quantity: 50, yoyo: false, seamless: true }); ``` **Multiple emission zones:** Pass an array to `emitZone` or call `addEmitZone()` multiple times. Zones iterate in sequence. The `total` property controls how many particles emit before rotating to the next zone (-1 = never rotate). ```js this.add.particles(400, 300, 'spark', { emitZone: [ { type: 'random', source: new Phaser.Geom.Circle(0, 0, 50) }, { type: 'random', source: new Phaser.Geom.Circle(200, 0, 50) } ] }); ``` ### Death Zones A `DeathZone` kills particles when they enter (or leave) a region. The source must have a `contains(x, y)` method. ```js // Kill particles entering a rectangle this.add.particles(400, 100, 'spark', { speed: 200, lifespan: 5000, gravityY: 100, deathZone: { type: 'onEnter', source: new Phaser.Geom.Rectangle(300, 400, 200, 50) } }); // Kill particles leaving a circle (confine to area) this.add.particles(400, 300, 'spark', { speed: 100, lifespan: 5000, deathZone: { type: 'onLeave', source: new Phaser.Geom.Circle(400, 300, 150) } }); // Custom death zone source (any object with contains) emitter.addDeathZone({ type: 'onEnter', source: { contains: (x, y) => x > 600 && y > 400 } }); ``` ### Following a Game Object ```js const player = this.add.sprite(100, 100, 'player'); const emitter = this.add.particles(0, 0, 'spark', { speed: 50, lifespan: 800, scale: { start: 0.5, end: 0 } }); emitter.startFollow(player); // follow position emitter.startFollow(player, 10, -20); // with offset emitter.startFollow(player, 0, 0, true); // track visibility too emitter.stopFollow(); // Or via config: this.add.particles(0, 0, 'spark', { follow: player, followOffset: { x: 0, y: -20 } }); ``` ### Particle Callbacks ```js // Via config const emitter = this.add.particles(400, 300, 'spark', { speed: 100, lifespan: 2000, emitCallback: (particle, emitter) => { /* on emit */ }, deathCallback: (particle) => { /* on death */ } }); // Or set after creation emitter.onParticleEmit((particle, emitter) => { /* ... */ }); emitter.onParticleDeath((particle) => { /* ... */ }); // Iterate alive/dead particles emitter.forEachAlive((particle, emitter) => { /* particle.x, particle.lifeT */ }); ``` ### Duration, StopAfter, and Advance ```js // Auto-stop after 3 seconds (alive particles continue until they expire) this.add.particles(400, 300, 'spark', { speed: 100, duration: 3000 }); // Emit exactly 50 particles then stop this.add.particles(400, 300, 'spark', { speed: 100, stopAfter: 50 }); // Pre-warm: fast-forward 2 seconds so particles visible on first frame this.add.particles(400, 300, 'spark', { speed: 100, lifespan: 2000, advance: 2000 }); // Or manually: emitter.fastForward(2000, 50); ``` ### Particle Bounds (Bounce) ```js this.add.particles(400, 300, 'spark', { speed: 200, lifespan: 5000, bounce: 0.8, bounds: { x: 100, y: 100, width: 600, height: 400 }, collideLeft: true, collideRight: true, collideTop: true, collideBottom: true }); // Or: emitter.addParticleBounds(100, 100, 600, 400); ``` ### Texture Frames and Animations ```js // Random frame per particle this.add.particles(400, 300, 'flares', { frame: ['red', 'green', 'blue'] }); // Sequential frames cycling through with quantity per frame this.add.particles(400, 300, 'flares', { frame: { frames: ['red', 'green', 'blue'], cycle: true, quantity: 4 } }); // Particle animation (plays anim over particle lifetime) this.add.particles(400, 300, 'explosion', { anim: 'explode_anim', lifespan: 1000 }); // Multiple anims, randomly assigned this.add.particles(400, 300, 'sheet', {
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub