One of the many things that iOS 5 brought with it, is the possibility of creating cool particle systems using only UIKit. Particle systems are used for explosions, fire effects, smoke… They are most widely used in games, although you can find them almost everywhere.
To create particle systems, you only need two classes from the Quartz Core framework: CAEmitterLayer and CAEmitterCell. These two classes were introduced with iOS 5, and make the task of creating particle effects much easier. CAEmitterLayer inherits from CALayer, another Quartz Core class we used in our latest tutorial to take screenshots programmatically.
In this tutorial I will show you how to create a fireball using CAEmitterLayer and CAEmitterCell, so let’s get started.
Step 1: Create the Project
Create a new project in Xcode and select Single View Application. Name the project however you want, make sure that the ARC and storyboard options are checked, and click Next. Once you have created the project, you will need a PNG for the particles.
Step 2: Import Quartz Core Framework
Go to your project file, and in Targets, go to Linked Frameworks and Libraries and click on the plus button. Double click on QuarzCore.framework to add it to your project.
Step 3: Create a New UIView Subclass
Create a new Objective-C class, name it ParticleEmitter and set it as a subclass of UIView. In its header file, import the Quartz Core framework and declare a CAEmitterLayer variable.
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
@interface ParticleEmitter : UIView {
CAEmitterLayer *emitter;
}
@end
Step 4: Setting Up the UI
In the storyboard, select the View Controller’s view and in the right sidebar, in the Attributes Inspector, set its class to ParticleEmitter. Moreover, set its background to a dark color, otherwise you won’t see the fireball very well.
Step 5: Modifying the CALayer Property
You need to tell the UIKit that the CAEmitterLayer will be the root layer for our view, so you need to override the layerClass method. In ParticleEmitter.m, add the following code:
+ (Class)layerClass
{
return [CAEmitterLayer class];
}
Step 6: Setting the Particle System’s Attributes
The first thing you need to do is create the CAEmitterLayer and set its position and its size. In ParticleEmitter.m, in the awakeFromNib method, add this:
emitter = (CAEmitterLayer *)self.layer;
emitter.emitterPosition = CGPointMake(160, 240);
emitter.emitterSize = CGSizeMake(5, 5);
Now you need to create a CAEmitterCell and set its attributes. You can experiment with each of them to get the effect you want. The attributes I will set for this fireball are:
- birthRate: number of particles created per second.
- liteTime: number of seconds before a particle disappears.
- lifeTimeRange: variation of the lifeTime. If lifeTime is 2 and lifeTimeRange is 0.5, then the lifeTime of each particle will be between 1.5 and 2.5.
- color: the color of the particles.
- contents: the image used for the particle.
- velocity: velocity of each particle in points per second.
- velocityRange: like lifeTimeRange, but with velocity.
- emissionRange: the angle in which the cell will be emitted. Since we are going to create a fireball and this angle is in radians, we will set it yo 2*PI.
- scaleSpeed: the rate at which the particle changes its speed.
spin: rotation speed for each particle.
CAEmitterCell* cell = [CAEmitterCell emitterCell];
cell.birthRate = 200;
cell.lifetime = 3.0;
cell.lifetimeRange = 0.5;
cell.color = [[UIColor colorWithRed:1.0 green:0.4 blue:0.2 alpha:0.1]
CGColor];
cell.contents = (id)[[[UIImage imageNamed:@"particle"] CGImage];
cell.velocity = 10;
cell.velocityRange = 20;
cell.emissionRange = 2*M_PI;
cell.scaleSpeed = 0.6;
cell.spin = 1;
Finally, add the cell you created to the emitter and change its render mode to kCAEmitterLayerAdditive, which will make it seem like fire.
emitter.emitterCells = [NSArray arrayWithObject:cell];
emitter.renderMode = kCAEmitterLayerAdditive;
Conclusion
With these two new classes, creating cool effects such as fire or smoke is much easier. Create your own particle systems playing with the attributes of each of these two classes, and write a comment if you have any doubt.