UIKit Particle Systems in iOS 5 Tutorial
Update 10/24/12: If you’d like a new version of this tutorial fully updated for iOS 6 and Xcode 4.5, check out iOS 5 by Tutorials Second Edition! Note from Ray: This is the fifteenth and final iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book […] By Ray Wenderlich.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
UIKit Particle Systems in iOS 5 Tutorial
20 mins
Let’s Start Emitting!
It’s time to add the code to make our CAEmitterLayer do its magic!
Open DWFParticleView.m, and add the following code at the end of awakeFromNib:
//configure the emitter layer
fireEmitter.emitterPosition = CGPointMake(50, 50);
fireEmitter.emitterSize = CGSizeMake(10, 10);
This sets the position of the emitter (in view local coordinates) and the size of the particles to spawn.
Next, add some more code to the bottom of awakeFromNib to add a CAEmitterCell to the CAEmitterLayer so we can finally see some particles on the screen!
CAEmitterCell* fire = [CAEmitterCell emitterCell];
fire.birthRate = 200;
fire.lifetime = 3.0;
fire.lifetimeRange = 0.5;
fire.color = [[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1]
CGColor];
fire.contents = (id)[[UIImage imageNamed:@"Particles_fire.png"] CGImage];
[fire setName:@"fire"];
//add the cell to the layer and we're done
fireEmitter.emitterCells = [NSArray arrayWithObject:fire];
We’re creating a cell instance and setting up few properties. Then we set the emitterCells property on the layer, which is just an NSArray of cells. The moment emitterCells is set, the layer starts to emit particles!
Next set set some properties on the CAEmitterCell. Let’s go over these one by one:
- birthRate: The number of emitted particles per second. For a good fire or waterfall you need at least few hundred particles, so we set this to 200.
- lifetime: The number of seconds before a particle should disappear. We set this to 3.0.
- lifetimeRange: You can use this to vary the lifetime of particles a bit. The system will give each individual a random lifetime in the range (lifetime – lifetimeRange, lifetime + lifetimeRange). So in our case, a particle will live from 2.5-3.5 seconds.
- color: The color tint to apply to the contents. We choose an orange color here.
- contents: The contents to use for the cell, usually a CGImage. We set it to our particle image.
- name: You can set a name for the cell in order to look it up and change its properties at a later point in time.
Run the app, and check out our new particle effect!
Well it works, but isn’t as cool as we might like. You might barely even be able to tell it’s doing something, it just looks like an orange splotch!
Let’s change this a bit to make the particle effect more dynamic. Add this code just before calling setName: on the cell:
fire.velocity = 10;
fire.velocityRange = 20;
fire.emissionRange = M_PI_2;
Here we’re setting the following new properties on the CAEmitterCell:
- velocity: The particles’s velocity in points per second. This will make our cell emit particles and send them towards the right edge of the screen
- velocityRange: This is the range by which the velocity should vary, similar to lifetimeRange.
- emissionRange: This is the angle range (in radians) in which the cell will emit. M_PI_2 is 45 degrees (and since this is the a range, it will be +/- 45 degrees).
Compile and run to check out the progress:
OK this is better – we’re not far from getting there! If you want to better understand how these properties affect the particle emitter – feel free to play and try tweaking the values and see the resulting particle systems.
Add two more lines to finish the cell configuration:
fire.scaleSpeed = 0.3;
fire.spin = 0.5;
Here we set two more properties on the CAEmitterCell:
- scaleSpeed: The rate of change per second at which the particle changes its scale. We set this to 0.3 to make the particles grow over time.
- spin: Sets the rotation speed of each particle. We set this to 0.5 to give the particles a nice spin.
Hit Run one more time:
By now we have something like a rusty smoke – and guess what? CAEmitterCell has a lot more properties to tweak, so kind of the sky is the limit here. But we’re going to leave it like that and go on with setting some configuration on the CAEmitterLayer. Directly after setting fireEmitter.emitterSize in the code add this line:
fireEmitter.renderMode = kCAEmitterLayerAdditive;
This is the single line of code which turns our rusty smoke into a boiling ball of fire. Hit Run and check the result:
What’s happening? The additive render mode basically tells the system not to draw the particles one over each other as it normally does, but to do something really cool: if there are overlapping particle parts – their color intensity increases! So, in the area where the emitter is – you can see pretty much a boiling white mass, but at the outer ranges of the fire ball – where the particles are already dying and there’s less of them, the color tints to it’s original rusty color. Awesome!
Now you might think this fire is pretty unrealistic – indeed, you can have much better fire by playing with the cell’s properties, but we need such a thick one because we’re going to draw with it. When you drag your finger on the device’s screen there’s relatively few touch positions reported so we’ll use a thicker ball of fire to compensate for that.
Play With Fire!
Now you finally get to play with fire (even though you’ve been told not to your entire life!) :]
To implement drawing on the screen by touching we’ll need to change the position of the emitter according to the user’s touch.
First declare a method for that in DWFParticleView.h:
-(void)setEmitterPositionFromTouch: (UITouch*)t;
Then implement the method in DWFParticleView.m:
-(void)setEmitterPositionFromTouch: (UITouch*)t
{
//change the emitter's position
fireEmitter.emitterPosition = [t locationInView:self];
}
This method gets a touch as a parameter and sets the emitterPosition to the position of the touch inside the view – pretty easy.
Next we’ll need an outlet for our view so we can tweak it from the view controller. Open DWFViewController.h and replace the code with the following:
#import <UIKit/UIKit.h>
#import "DWFParticleView.h"
@interface DWFViewController : UIViewController
{
IBOutlet DWFParticleView* fireView;
}
@end
As you see we import our custom view class and we declare an instance variable for the DWFParticleView.
Next open DWFViewController.xib and control-drag from the File’s Owner to the root view, and choose fireView from the popup:
Now we can access the emitter layer from the view controller. Open DWFViewController.m, remove all the boilerplate methods from the implementation, and add this instead:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[fireView setEmitterPositionFromTouch: [touches anyObject]];
}
Now hit Run – touch and drag around and you’ll see the emitter moving and leaving a cool trail of fire! Try dragging your finger on the screen slower or faster to see the effect it generates.