Search code examples
iosobjective-ciphonecore-animationparticle-system

CAEmitterLayer emit continuously in a line


I am creating a very simple particle system with CoreAnimation.

This is my cell:

UIImage *image = [UIImage imageNamed:@"spark"];
CAEmitterCell *cell = [CAEmitterCell emitterCell];
[cell setContents:(id)image.CGImage];
[cell setBirthRate:250.f];
[cell setScale:.25f];
[cell setColor:[UIColor colorWithRed:1.0 green:0.2 blue:0.1 alpha:0.5].CGColor];
[cell setLifetime:5.0f];

and layer:

CAEmitterLayer *emitterLayer = [CAEmitterLayer layer];
[emitterLayer setEmitterCells:@[cell]];
[emitterLayer setFrame:bounds];
[emitterLayer setRenderMode:kCAEmitterLayerAdditive];
[self.view.layer addSublayer:emitterLayer];

Now, I move the emitterLayer's position to wherever I'm touching:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    self.emitterLayer.emitterPosition = [[touches anyObject] locationInView:self.view];
}

However, the problem is, it doesn't emit the particles continuously. But rather, at regular intervals(dotted as oppose to a line):

enter image description here

I thought perhaps it's because I'm not animating it. So I tried to add a simple animation to move the emitter from top left to bottom right of the screen just to see if that works:

CGPoint startPos = CGPointZero;
CGPoint endPos = CGPointMake(bounds.size.width, bounds.size.height);

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"emitterPosition"];
ba.fromValue = [NSValue valueWithCGPoint:startPos];
ba.toValue = [NSValue valueWithCGPoint:endPos];
ba.duration = .5f;
[emitterLayer addAnimation:ba forKey:nil];

What I expected is a line be be formed with particles emitted continuously. However, what I see particles being emitted at intervals, like this:enter image description here

Is it possible to have the emitterLayer follow your touch up and continuously emit these particles like a drawing and not be dotted?

Thanks


Solution

  • The effect you are looking to achieve (I saw a link in a comment) is probably best achieved without a particle system. What you usually use for this effect depends on individual approach, but I've had success with both.

    One, is to create a render buffer: You draw directly onto this buffer with a colour at maximum value. This could be a UIView for instance. At a timed interval, you decrease every pixel value in this view by a percentage (say 0.05%). New pixels added start bright and fade over time this way, so you have no gaps between points. This is CPU intensive!

    The other is to create a 'trianglestrip': you will need to go into a lower level graphics API for this such as OpenGL. The idea is that you create a section of triangles (or quads) that form a 'ribbon' under your finger. Each new section that is added begins fading to 0% alpha and is then removed. There is an implementation of this technique in cocos2d which is called CCMotionStreak that is perfect for this. The benefit is that you supply a texture (as you would a particle system) so it keeps designers happy