Class

SKEmitterNode

A node that creates and renders particles.

Overview

A SKEmitterNode object is a node that automatically creates and renders small particle sprites. Particle sprites are privately owned by SpriteKit—your game cannot access the generated sprites. For example, this means you cannot add physics shapes to particles. Emitter nodes are often used to create smoke, fire, sparks, and other particle effects. A particle is similar to an SKSpriteNode object; it renders a textured or untextured image that is sized, colorized, and blended into the scene. However, particles differ from sprites in two important ways:

  • A particle’s texture is always stretched uniformly.

  • Particles are not represented by objects in SpriteKit. This means you cannot perform node-related tasks on particles, nor can you associate physics bodies with particles to make them interact with other content. Although there is no visible class representing particles added by the emitter node, you can think of a particle as having properties like any other object.

Particles are purely visual objects, and their behavior is entirely defined by the emitter node that created them. The emitter node contains many properties to control the behavior of the particles it spawns, including:

  • The birth rate and lifetime the particle. You can also specify the maximum number of particles that are spawned before the emitter turns itself off and the order in which the particles are rendered.

  • The starting values of the particle, including its position, orientation, color, and size. You can choose to have these starting values randomized.

  • The changes to apply to the particle over its lifetime. Typically, these are specified as a rate-of-change over time. For example, you might specify that a particle rotates at a particular rate, in radians per second. The emitter automatically updates the particle data each frame. In most cases, you can also create more sophisticated behaviors using keyframe sequences. For example, you might specify a keyframe sequence for a particle so that it starts out small, scales up to a larger size, then shrinks before dying.

Use the Particle Emitter Editor to Experiment with Emitters

In most cases, you never need to configure an emitter node directly in your game. Instead, you use Xcode to configure an emitter node’s properties. As you change the behavior of the emitter node, Xcode immediately provides you an updated visual effect. When complete, Xcode archives the configured emitter. Then, at runtime, your game uses this archive to instantiate a new emitter node.

Using Xcode to create your emitter nodes has a few important advantages:

  • It is the best way to learn the capabilities of the emitter class.

  • You can more quickly experiment with new particle effects and see the results immediately.

  • You separate the task of designing a particle effect from the programming task of using it. Your artists can work on new particle effects independent of your game code.

For more information on using Xcode to create particle effects, see Particle Emitter Editor Guide.

SKEmitterNode shows how to load a particle effect that was created by Xcode. All particle effects are saved using Cocoa’s standard archiving mechanisms, so the code first creates a path to the smoke effect, and then loads the archive.

Listing 1

Loading a particle effect from a file

- (SKEmitterNode *) newSmokeEmitter
{
    NSString *smokePath = [[NSBundle mainBundle] pathForResource:@"smoke" ofType:@"sks"];
    SKEmitterNode *smoke = [NSKeyedUnarchiver unarchiveObjectWithFile:smokePath];
    return smoke;
}

Manually Configuring Particle Creation

The SKEmitterNode class provides many properties for configuring an emitter node’s behavior. The Xcode inspector sets the same property values. You can also create and configure your own emitter, or you can take an emitter node created in the Particle Emitter Editor, load it, and change its property values. For example, assume for a moment that you are using the smoke effect in SKEmitterNode to show damage to a rocket ship. As the ship takes more damage, you could increase the birth rate of the emitter to add more smoke.

When the emitter node is in a scene, it emits new particles. You use the following properties to define how many particles it creates:

  • The particleBirthRate property specifies the number of particles that the emitter creates every second.

  • The numParticlesToEmit property specifies how many particles are created before the emitter turns itself off. You can also configure the node to emit an unlimited number of particles.

When a particle is created, its initial property values are determined by the properties of the emitter. For each of the particle’s properties, the emitter class declares up to four properties:

  • The average starting value for the property.

  • A random range for values of the property. Each time a new particle is emitted, a new random value is calculated within that range.

  • The rate at which the value changes over time, also known as the property’s speed. Not all properties have a speed property.

  • An optional keyframe sequence.

The complete list of properties used to configure an emitter node is described in SKEmitterNode.

SKEmitterNode shows how you might configure an emitter’s scale property. This is a simplified version of a node’s xScale and yScale properties, and determines how large the particle is.

Listing 2

Configuring a particle’s scale properties

myEmitter.particleScale = 0.3;
myEmitter.particleScaleRange = 0.2;
myEmitter.particleScaleSpeed = -0.1;

When a new particle is created, its scale value is a random number from 0.2 to 0.4. The scale value then decreases at a rate of 0.1 per second. So, if a particular particle started at the average value, 0.3, it would decrease from 0.3 to 0 over a period of 3 seconds.

Using Keyframe Sequences to Configure Custom Ramps for a Particle Property

Keyframe sequences provide more sophisticated behaviors for a particle property. A keyframe sequence specifies multiple points in a particle’s lifetime and specifies the value for a property at each point. The keyframe sequence then interpolates values between those points and uses them to simulate the particle’s property value.

You can use keyframe sequences to implement many custom behaviors, including:

  • Changing a property value until it reaches a specific value.

  • Using multiple different property values over the lifetime of a particle. For example, you might increase the value of the property in one part of the sequence and decrease it in another. Or, when specifying colors, you might specify multiple colors that the particle cycles through during its lifetime.

  • Changing a property value using a nonlinear curve or a stepping function.

SKEmitterNode shows how you might replace the code in SKEmitterNode to use a sequence. When you use a sequence, the values are not randomized. Instead, the sequence specifies all of the values of the property. Each keyframe value includes a value object and a timestamp. The timestamps are specified in a range from 0 to 1.0, where 0 represents the birth of the particle and 1.0 represents its death. So, for this sequence, the particle starts out with a scale of 0.2 and increases to 0.7 one quarter of the way through the sequence. Three quarters of the way through the sequence, it reaches its minimum size, 0.1. It remains at this size until it dies.

Listing 3

Using a sequence to change a particle’s scale property

SKKeyframeSequence  *scaleSequence = [[SKKeyframeSequence alloc] initWithKeyframeValues:@[@0.2,@0.7,@0.1] times:@[@0.0,@0.250,@0.75]];
myEmitter.particleScaleSequence = scaleSequence;

Adding Actions to Particles

Although you do not have direct access to the particles created by SpriteKit, you can specify an action that all particles execute. Whenever a new particle is created, the emitter tells the particle to run that action. You can use actions to create very sophisticated behaviors.

For the purpose of using actions on particles, you can treat the particle as if it were a sprite. This means you can perform other interesting tricks, such as animating the particle’s textures.

Using Target Nodes to Change the Destination of Particles

When the emitter creates particles, they are rendered as children of the emitter node. This means that they inherit the characteristics of the emitter node, just like nodes do. For example, if you rotate the emitter node, the positions of all of the spawned particles are rotated also. Depending on what effect you are simulating with the emitter, this may not be the correct behavior. For example, assume that you are using the emitter node to create the exhaust from a rocket. When the engines are at full burn, a cone of flame should come out the back of the ship. This is easily simulated using particles. But if the particles are rendered relative to the ship, when the ship turns, the exhaust is going to rotate as well. That doesn’t look right. What you really want is for the particles to be spawned, but thereafter be independent of the emitter node. When the emitter node is rotated, new particles get the new orientation, and old particles maintain their old orientation. You make particles independent of the emitter by specifying a target node.

SKEmitterNode shows how to configure a rocket exhaust effect to use a target node. When the custom sprite node class instantiates the exhaust node, it makes the node its child. However, it redirects the particles to the scene.

Listing 4

Using a target node to redirect where particles are spawned

- (void) newExhaustNode
{
    SKEmitterNode *emitter =  [NSKeyedUnarchiver unarchiveObjectWithFile:[[NSBundle mainBundle] pathForResource:@"exhaust" ofType:@"sks"]];
 
// Place the emitter at the rear of the ship.
   emitter.position = CGPointMake(0,-40);
   emitter.name = @"exhaust";
// Send the particles to the scene.
   emitter.targetNode = self.scene;
 
   [self addChild:emitter];
}

When an emitter has a target node, it calculates the position, velocity, and orientation of the particle, exactly as if it were a child of the sprite node. This means that if the ship sprite is rotated, the exhaust orientation is automatically rotated also. However, at the moment a new particle’s starting values are calculated, the values are transformed into the target node’s coordinate system. Thereafter, they would only be affected by changes to the target node.

Particle Emitter Tips

Particle emitters in SpriteKit are one of the most powerful tools for building visual effects. However, used incorrectly, particle emitters can be a bottleneck in the design and implementation of your app. Consider the following tips:

  • Use Xcode to create and test your particle effects, then load the archives in your game.

  • Adjust emitter properties sparingly inside your game code. Typically, you do this to specify properties that cannot be specified in the Xcode inspector or to control properties inside your game logic.

  • Particles are cheaper than a sprite node, but they still have overhead! Try to keep the number of particles onscreen to a minimum by creating particle emitters with a low birth rate, and specifying a short lifetime for particles. For example, instead of creating hundreds or thousands of particles per second, reduce the birth rate and increase the size of the particles slightly. Often, you can create effects with fewer particles but the same net visual appearance.

  • Use actions on particles only when there isn’t another solution. Executing actions on individual particles is potentially very expensive, especially if the particle emitter also has a high birth rate.

  • Assign a target node whenever the particles should be independent of the emitter node after they are spawned. For examples, particles should be independent if the emitter node moves or rotates in the scene.

  • Consider removing a particle emitter from the scene when it is not visible onscreen. Add it just before it becomes visible.

Symbols

Determining When Particles Are Created

func advanceSimulationTime(TimeInterval)

Advances the emitter particle simulation.

func resetSimulation()

Removes all existing particles and restarts the simulation.

var particleBirthRate: CGFloat

The rate at which new particles are created.

var numParticlesToEmit: Int

The number of particles the emitter should emit before stopping.

var particleRenderOrder: SKParticleRenderOrder

The order in which the emitter’s particles are rendered.

Defining Which Node Emits Particles

var targetNode: SKNode?

The target node which renders the emitter’s particles.

Determining a Particle Lifetime

var particleLifetime: CGFloat

The average lifetime of a particle, in seconds.

var particleLifetimeRange: CGFloat

The range of allowed random values for a particle’s lifetime.

Determining a Particle’s Initial Position

var particlePosition: CGPoint

The average starting position for a particle.

var particlePositionRange: CGVector

The range of allowed random values for a particle’s position.

var particleZPosition: CGFloat

The average starting depth of a particle.

var particleZPositionRange: CGFloat

The range of allowed random values for a particle’s depth.

Deprecated

Determining a Particle’s Velocity and Acceleration

var particleSpeed: CGFloat

The average initial speed of a new particle in points per second.

var particleSpeedRange: CGFloat

The range of allowed random values for a particle’s initial speed.

var emissionAngle: CGFloat

The average initial direction of a particle, expressed as an angle in radians.

var emissionAngleRange: CGFloat

The range of allowed random values for a particle’s initial speed, expressed as an angle in radians.

var xAcceleration: CGFloat

The acceleration to apply to a particle’s horizontal velocity.

var yAcceleration: CGFloat

The acceleration to apply to a particle’s vertical velocity.

var particleZPositionSpeed: CGFloat

The speed at which the particle’s depth changes.

Deprecated

Determining a Particle’s Rotation

var particleRotation: CGFloat

The average initial rotation of a particle, expressed as an angle in radians.

var particleRotationRange: CGFloat

The range of allowed random values for a particle’s initial rotation, expressed as an angle in radians.

var particleRotationSpeed: CGFloat

The speed at which a particle rotates, expressed in radians per second.

Determining a Particle’s Scale Factor

var particleScaleSequence: SKKeyframeSequence?

The sequence used to specify the scale factor of a particle over its lifetime.

var particleScale: CGFloat

The average initial scale factor of a particle.

var particleScaleRange: CGFloat

The range of allowed random values for a particle’s initial scale.

var particleScaleSpeed: CGFloat

The rate at which a particle’s scale factor changes per second.

Setting a Particle’s Texture and Size

var particleTexture: SKTexture?

The texture to use to render a particle.

var particleSize: CGSize

The starting size of each particle.

Configuring Particle Color

var particleColorSequence: SKKeyframeSequence?

The sequence used to specify the color components of a particle over its lifetime.

var particleColor: UIColor

The average initial color for a particle.

var particleColorAlphaRange: CGFloat

The range of allowed random values for the alpha component of a particle’s initial color.

var particleColorBlueRange: CGFloat

The range of allowed random values for the blue component of a particle’s initial color.

var particleColorGreenRange: CGFloat

The range of allowed random values for the green component of a particle’s initial color.

var particleColorRedRange: CGFloat

The range of allowed random values for the red component of a particle’s initial color.

var particleColorAlphaSpeed: CGFloat

The rate at which the alpha component of a particle’s color changes per second.

var particleColorBlueSpeed: CGFloat

The rate at which the blue component of a particle’s color changes per second.

var particleColorGreenSpeed: CGFloat

The rate at which the green component of a particle’s color changes per second.

var particleColorRedSpeed: CGFloat

The rate at which the red component of a particle’s color changes per second.

Determining How the Particle Texture Is Blended with the Particle Color

var particleColorBlendFactorSequence: SKKeyframeSequence?

The sequence used to specify the color blend factor of a particle over its lifetime.

var particleColorBlendFactor: CGFloat

The average starting value for the color blend factor.

var particleColorBlendFactorRange: CGFloat

The range of allowed random values for a particle’s starting color blend factor.

var particleColorBlendFactorSpeed: CGFloat

The rate at which the color blend factor changes per second.

Blending Particles with the Framebuffer

var particleBlendMode: SKBlendMode

The blending mode used to blend particles into the framebuffer.

var particleAlphaSequence: SKKeyframeSequence?

The sequence used to specify the alpha value of a particle over its lifetime.

var particleAlpha: CGFloat

The average starting alpha value for a particle.

var particleAlphaRange: CGFloat

The range of allowed random values for a particle’s starting alpha value.

var particleAlphaSpeed: CGFloat

The rate at which the alpha value of a particle changes per second.

Adding an Action to Particles

var particleAction: SKAction?

Specifies an action executed by new particles.

Applying Physics Fields to the Particles

var fieldBitMask: UInt32

A mask that defines which categories of physics fields can exert forces on the particles.

Using a Custom Shader to Render the Particles

var shader: SKShader?

A custom shader used to determine how particles are rendered.

Constants

SKParticleRenderOrder

Order to use when the emitter’s particles are rendered.

Relationships

Inherits From

Conforms To