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.

소스 정보

저장소
phaserjs/phaser
최근 소스 활동
2026년 4월 10일 12:38
감지된 SKILL.md 언어
영어
스타
40,673
포크
7,186

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
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', {
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기