iOS Recipes - Matt Drance [58]
SimpleEmitter/SimpleEmitter/PRPSimpleEmitterLayer.m
- (void)start {
self.imageLayer.frame = self.bounds;
self.imageLayer.opacity = 1.0;
self.instanceCount = count;
self.instanceDelay = cycleTime/count;
CATransform3D t = CATransform3DMakeRotation(self.rotator, 0, 0, 1);
self.instanceTransform = CATransform3DTranslate(t,
xAdjust,
yAdjust, 0);
self.transform = CATransform3DMakeRotation(angle, 0, 0, 1);
[self animate];
}
We use a now-familiar CABasicAnimation object to animate the position of the imagelayer. We only need be concerned with distance of movement at this point, because we later rotate the imagelayer to point the emitted particles in any direction we want. So, the newPoint value need only be based on the length property.
SimpleEmitter/SimpleEmitter/PRPSimpleEmitterLayer.m
-(void)animate {
CGPoint newPoint = CGPointMake(0, length);
CABasicAnimation *basic = [CABasicAnimation animation];
basic.keyPath = @"position";
basic.toValue = [NSValue valueWithCGPoint:newPoint];
basic.duration = self.cycleTime;
basic.repeatCount = MAXFLOAT;
[imageLayer addAnimation:basic forKey:@"position"];
}
Stopping the emitter simply involves removing the animation and setting the imageLayer opacity to zero.
SimpleEmitter/SimpleEmitter/PRPSimpleEmitterLayer.m
- (void)stop {
self.imageLayer.opacity = 0;
self.instanceCount = 0;
[self.imageLayer removeAllAnimations];
}
Setting up an emitter from the view controller looks a lot more complicated than it is. We instantiate the layer just like any other and set its origin to act as the center of the emitter and its frame size to the size of the particle. With the combination of the properties from the replicator layer and the new properties on the simple emitter layer, we have a lot of values we can play with to create different effects. In the SimpleEmitterViewController class, we have a set of emitter methods, each of which produces quite different results. emitter1 produces a spiral effect because it defines an incremental rotator angle, which needs to be quite small because we have 100 “particles.” We also modify the color slightly for each particle by setting the instanceGreenOffset property to a small negative value, slowly reducing the green element of the color; we do the same for the red and blue elements.
SimpleEmitter/SimpleEmitter/SimpleEmitterViewController.m
-(PRPSimpleEmitterLayer *)emitter1 {
CGFloat w = self.view.frame.size.width;
CGFloat h = self.view.frame.size.height;
PRPSimpleEmitterLayer *emitter =
[PRPSimpleEmitterLayer layer];
emitter.frame = CGRectMake(w/4, h/2, 16,16);
emitter.rotator = -M_PI*4/50;
emitter.length = w/4;
emitter.count = 100;
emitter.angle = 2.5;
emitter.cycleTime = 1.0;
emitter.instanceGreenOffset = -0.1/emitter.count;
emitter.instanceRedOffset = -0.5/emitter.count;
emitter.instanceBlueOffset = -0.1/emitter.count;
[self.view.layer addSublayer:emitter];
return emitter;
}
In the emitter4 method, we also override the instanceColor value to set the particle to red and set the sublayer image to a BrightBlob image instead of the default spark.
SimpleEmitter/SimpleEmitter/SimpleEmitterViewController.m
-(PRPSimpleEmitterLayer *)emitter4 {
CGFloat w = self.view.frame.size.width;
CGFloat h = self.view.frame.size.height;
PRPSimpleEmitterLayer *emitter =
[PRPSimpleEmitterLayer layer];
emitter.frame = CGRectMake(0, h, 16,16);
emitter.rotator = 0.02;
emitter.length = w;
emitter.count = 6;
emitter.angle = 4.0;
emitter.cycleTime = 1.6;
emitter.instanceColor = [UIColor redColor].CGColor;
emitter.imageLayer.contents =
(id)[UIImage imageNamed:@"brightBlob.png"].CGImage;
[self.view.layer addSublayer:emitter];
return emitter;
}
The four samples in the view controller show how making small changes to the various properties of the emitter