z2k
z2k

Reputation: 10380

How can I EaseIn/Out SKEmitterNode.particleBirthRate

I'm using a SKEmitterNode to emit some particles on tap. I'm after an effect similar to the hearts in Periscope.

I find that when I add the emitter it doesn't behave like it was just "turned on". That is, particles appear with full alpha far from the spawn point (as if they've been alive for a while). It is as if the emitter has been running it was suddenly shown.

What I'm after is tap -> add node-> start emitting from point -> emit for a while -> shut off -> remove node.

I've tried adjusting the particleBirthRate using GCD:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if(self.burstEmitter.parent){
        return;
    }

    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInNode:self];
    self.burstEmitter.position = point;
    self.burstEmitter.particleBirthRate = 0;
    [self addChild:self.burstEmitter];


    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.burstEmitter.particleBirthRate = 10;
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            self.burstEmitter.particleBirthRate = 0;

            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self removeAllChildren];
            });
        });
    });
}

Then I though SKAction might be the right tool (it probably is...)

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if(self.burstEmitter.parent){
        return;
    }

    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInNode:self];
    self.burstEmitter.position = point;
    self.burstEmitter.particleBirthRate = 10;
    [self addChild:self.burstEmitter];


    [self.burstEmitter runAction:[SKAction sequence:@[
                                                      [SKAction fadeInWithDuration:1],
                                                      [SKAction waitForDuration:2],
                                                      [SKAction fadeOutWithDuration:1],
                                                      [SKAction removeFromParent]
                                                      ]]];
}

This obviously fades the emitter node out, not "shut it off",

I'm open to using CAEmitterLayer. I tried that as well but ran into the same issue.


Update: I found one solution: resetSimulation.

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if(self.burstEmitter.parent){
        return;
    }

    UITouch *touch = [touches anyObject];
    CGPoint point = [touch locationInNode:self];
    self.burstEmitter.position = point;
    self.burstEmitter.particleBirthRate = 10;
    [self.burstEmitter resetSimulation];
    [self addChild:self.burstEmitter];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.burstEmitter.particleBirthRate = 0;

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [self removeAllChildren];
        });
    });
}

This accomplishes what I was after. I'm still curious to use SKAction for this if possible.

Upvotes: 1

Views: 153

Answers (2)

matt
matt

Reputation: 534893

Use an SKKeyframeSequence. That's what it's for.

See the discussion of "Using Keyframe Sequences to Configure Custom Ramps for a Particle Property" on the SKEmitterNode docs page.

Upvotes: 1

sangony
sangony

Reputation: 11696

You can use a SKAction block. There are a number of ways to accomplish what you are asking. Here is a simple one:

SKAction *wait0 = [SKAction waitForDuration:0.5]; // time in secs
SKAction *block0 = [SKAction runBlock:^{
    self.burstEmitter.particleBirthRate = 9;
}];
SKAction *block1 = [SKAction runBlock:^{
    self.burstEmitter.particleBirthRate = 8;
}];
SKAction *block2 = [SKAction runBlock:^{
    self.burstEmitter.particleBirthRate = 7;
}];

// and so on...

[self runAction:[SKAction sequence:@[block0, wait0, block1, wait0, block2]]];

Upvotes: 1

Related Questions