Reputation: 10380
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
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
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