@basementuniverse/particles-2d
v1.2.1
Published
A component for animating and rendering particles in 2d games
Downloads
16
Readme
Game Component: Particle System 2D
A basic particle system component for use in 2d games.
Installation
npm install @basementuniverse/particles-2dHow to use
See /demos for some examples.
- Import the component and any other classes you need:
import {
ParticleSystem,
Emitter,
Attractor,
ForceField,
Collider,
} from '@basementuniverse/particles-2d';- Create a
ParticleSysteminstance:
const particleSystem = new ParticleSystem();- Add emitters, attractors, force fields, and colliders as needed:
particleSystem.emitters.push(
new Emitter(/* See below for options */)
);
particleSystem.attractors.push(
new Attractor(/* See below for options */)
);
particleSystem.forceFields.push(
new ForceField(/* See below for options */)
);
particleSystem.colliders.push(
new Collider(/* See below for options */)
);- Update and render the particle system in your game loop:
function update(deltaTime) {
particleSystem.update(deltaTime);
// Other game logic...
}
function draw(context) {
particleSystem.draw(context);
// Other rendering logic...
}Utility types
vec2
{ x: number, y: number }Color
{ r: number, g: number, b: number, a?: number }Emitters
Emitters are responsible for generating and emitting particles.
new Emitter(
position: vec2, // { x: number, y: number }
size: vec2, // { x: number, y: number }
lifespan: number, // in seconds, use -1 for infinite lifespan
options?: EmitterOptions // see below...
);Emitter Options
{
particles: {
position
speed
direction
size
rotation
lifespan
style
options
},
emission: {
type
rate, n, delay, f // depends on type
}
}particles.position
Define the initial position of particles:
'uniform': particles will be uniformly distributed within the emitter's area as defined by itsposition(this is the center) andsize'normal': particles will be normally distributed within the emitter's area, i.e. more particles will be generated near the center of the emitter and fewer towards the edges(n: number) => vec2: a function that returns a position for each particle, wherenis the index of the particle being emitted (maybe useful if we're emitting multiple particles in a single frame)
particles.speed
Define the initial speed of particles:
number: a constant speed for all particles{ min: number, max: number }: a range of speeds for particles, each particle will have a random speed within this range(n: number) => number: a function that returns a speed for each particle, wherenis the index of the particle being emitted
particles.direction
Define the initial direction of particles in radians (0 is right):
number: a constant direction for all particles{ min: number, max: number }: a range of directions for particles, each particle will have a random direction within this range(n: number) => number: a function that returns a direction for each particle, wherenis the index of the particle being emitted
particles.size
Define the initial size of particles:
{ x: number, y: number }: a constant size for all particles{ min: { x, y }, max: { x, y } }: a range of sizes for particles, each particle will have a random size within this range(n: number) => { x: number, y: number }: a function that returns a size for each particle, wherenis the index of the particle being emitted
particles.rotation
Define the initial rotation of particles in radians (0 is right):
null: rotation will be calculated based on the particle's velocitynumber: a constant rotation for all particles{ min: number, max: number }: a range of rotations for particles, each particle will have a random rotation within this range(n: number) => number: a function that returns a rotation for each particle, wherenis the index of the particle being emitted
particles.lifespan
Define the lifespan of particles in seconds:
number: a constant lifespan for all particles{ min: number, max: number }: a range of lifespans for particles, each particle will have a random lifespan within this range(n: number) => number: a function that returns a lifespan for each particle, wherenis the index of the particle being emitted
particles.style
There are a few default "built-in" styles:
{
// the size of the dot will be max(size.x, size.y)
style: 'dot';
color: Color | string | Color[] | string[]; // fixed or random color
glow?: {
color: Color | string | Color[] | string[];
amount: number;
};
fade?: {
in: number; // fade in duration in seconds
out: number; // fade out duration in seconds
};
}{
// the size of the radial gradient will be max(size.x, size.y)
style: 'radial';
color: Color | string | Color[] | string[]; // fixed or random color
fade?: {
in: number; // fade in duration in seconds
out: number; // fade out duration in seconds
};
}{
// the length of the line will be size.x, and the width will be size.y
style: 'line';
color: Color | string | Color[] | string[];
rotationOffset?: number; // how much to offset the particle's rotation in radians
glow?: {
color: Color | string | Color[] | string[];
amount: number;
};
fade?: {
in: number; // fade in duration in seconds
out: number; // fade out duration in seconds
};
}{
// the size of the image is defined by size.x and size.y
style: 'image';
image: HTMLImageElement; // the image to render
rotationOffset?: number; // how much to offset the particle's rotation in radians
fade?: {
in: number; // fade in duration in seconds
out: number; // fade out duration in seconds
};
}particles.style.trail
Particles can optionally have a trail effect.
{
// the size of the image is defined by size.x and size.y
style: '...';
// other style options (see above)...
trail: {
length: number; // how many trail segments to keep
color?: Color | string | Color[] | string[]; // fixed or random color for the trail, if not provided we use the particle's color
width?: number; // width of the trail segments, if not provided we use the particle's size
widthDecay?: number; // how much to decay the width of the trail segments, 0 means no decay, 1 means full decay (the trail will disappear over its length), negative numbers cause the trail to grow wider over its length
segmentFade?: {
in: number; // how many segments to fade in at the start of the trail
out: number; // how many segments to fade out at the end of the trail
};
}
}particles.options
{
useAttractors: boolean; // whether particles from this emitter should be affected by attractors
useForceFields: boolean; // whether particles from this emitter should be affected by force fields
useColliders: boolean; // whether particles from this emitter should be affected by colliders
defaultUpdates: 'none' | 'all' | ParticleDefaultUpdateTypes;
update?: (system: ParticleSystem, dt: number) => void;
defaultDraws: 'none' | 'all' | ParticleDefaultDrawTypes;
preDraw?: (system: ParticleSystem, context: CanvasRenderingContext2D) => void;
postDraw?: (system: ParticleSystem, context: CanvasRenderingContext2D) => void;
}Default update types:
age: update the age of particles and handle disposalphysics: update the velocity of particles based on forces, collisions, etc.direction: update the direction of particles based on their velocityposition: integrate the position of particles based on their velocity
Default draw types:
transforms: apply transformations like translation and rotationfade: apply fade in/out effects to particlesstyles: render the particle's style (dot, radial, line, image)
emission
Various particle emission types are available:
{
// emit some number of particles per second
type: 'rate';
rate: number | { min: number, max: number };
}If rate is a random range, the rate will be updated every second.
{
// emit some number of particles immediately and then automatically dispose the emitter
type: 'burst';
n: number | { min: number, max: number };
delay?: number; // optional delay in seconds before emitting
}{
// custom function, this will be called every frame and should return the number of particles to emit
type: 'custom';
f: () => number;
}Attractors
Attractors can attract or repel particles in range of the attractor.
new Attractor(
position: vec2, // { x: number, y: number }
range: number,
force: number, // negative for repulsion, positive for attraction
falloff: number,
lifespan: number // use -1 for infinite lifespan
);Force Fields
Force fields apply a force to all particles.
new ForceField(
force: vec2, // { x: number, y: number }
lifespan: number // use -1 for infinite lifespan
);Colliders
Colliders are used for detecting and handling collisions with particles.
new Collider(
geometry, // see below...
restitution: number, // how bouncy the collider is, 0 is no bounce, 1 is full bounce
friction: number, // how much friction the collider has, 0 is no friction, 1 is full friction
randomness: number // how much to randomly offset the direction of particles when they collide, 0 is no randomness, 1 is full randomness (the particle will be offset randomly +/- PI radians)
);Collider Geometry
Collider geometry can be defined in various ways:
{
type: 'circle';
position: vec2; // { x: number, y: number }
radius: number;
}{
type: 'rectangle';
position: vec2; // { x: number, y: number }
size: vec2; // { x: number, y: number }
rotation?: number; // optional rotation in radians
}{
type: 'polygon';
vertices: vec2[]; // array of vertices defining the polygon
}