我正在玩CAEmitterLayer,现在我遇到了一些问题:(
我需要一个短粒子效果 - 比如一个击球或爆炸 - 例如在一个地方(所以我在这个地方有小UIView)。我该怎么办?
1,我有一个想法 - 使用它的粒子创建emitterLayer并将lifeTime设置为0.当我需要它时,我将lifeTime设置为1,并且在一段时间之后我可以将其设置为0。 - 但它没有做任何事情:(
2,第二个想法是每次需要时创建[CAEmitterLayer图层]并将其添加为图层子图层。但是我在想,当我重复十次时会发生什么......我有10个子层,一个有效,9个“死”? 如何停止一般发射?我有一段时间后执行performSelector将生命周期设置为0,并将其他选择器设置为更长的间隔来删除.FromSuperlayer ...但它不是那么漂亮我想拥有它:(还有另一种“正确”方式吗?
我认为太多的子层与我的另一个问题有关...我只想发射一个粒子。当我这样做时,它有效。但是有时候它发出三个粒子,有时两个......这让我很生气。当我不停止发射器时,它每次给出正确数量的粒子......
所以问题......
如何在短时间内发射粒子。 如何使用它们 - 如停止,从父图层中删除,... 如何发出确切数量的粒子
编辑:
emitter = [CAEmitterLayer layer];
emitter.emitterPosition = CGPointMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2);
emitter.emitterMode = kCAEmitterLayerPoints;
emitter.emitterShape = kCAEmitterLayerPoint;
emitter.renderMode = kCAEmitterLayerOldestFirst;
emitter.lifetime = 0;
particle = [CAEmitterCell emitterCell];
[particle setName:@"hit"];
particle.birthRate = 1;
particle.emissionLongitude = 3*M_PI_2;//270deg
particle.lifetime = 0.75;
particle.lifetimeRange = 0;
particle.velocity = 110;
particle.velocityRange = 20;
particle.emissionRange = M_PI_2;//PI/2 = 90degrees
particle.yAcceleration = 200;
particle.contents = (id) [[UIImage imageNamed:@"50"] CGImage];
particle.scale = 1.0;
particle.scaleSpeed = -0.5;
particle.alphaSpeed = -1.0;
emitter.emitterCells = [NSArray arrayWithObject:particle];
[(CAEmitterLayer *)self.view.layer addSublayer: emitter];
然后在与按钮链接的方法中,我这样做:
emitter.lifetime = 1.0;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.9 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
emitter.lifetime = 0;
});
改为@DavidRönnqvist态度后改编和更新
CAEmitterCell *dustCell = [CAEmitterCell emitterCell];
[dustCell setBirthRate:1];
[dustCell setLifetime:1.5];
[dustCell setName:@"dust"];
[dustCell setContents:(id) [[UIImage imageNamed:@"smoke"] CGImage]];
[dustCell setVelocity:50];
[dustCell setEmissionRange:M_PI];
// Various configurations for the appearance...
// This is the only cell with configured scale,
// color, content, emissionLongitude, etc...
[emitter setEmitterCells:[NSArray arrayWithObject:dustCell]];
[(CAEmitterLayer *)self.view.layer addSublayer:emitter];
// After one burst, change the birth rate of the cloud to 0
// so that there is only one burst per side.
double delayInSeconds = 0.5; // One cloud will have been created by now, but not two
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
[emitter setLifetime:0.0];
[emitter setValue:[NSNumber numberWithFloat:0.0]
forKeyPath:@"emitterCells.dust.birthRate"];
});
答案 0 :(得分:10)
您可以通过配置一次(不要每次都添加新的发射器单元格)并将birthRate
设置为0(不会创建任何粒子)来完成此操作。然后,当您想要创建粒子时,可以将birthRate
设置为您想要创建的每秒粒子数。经过一段时间后,将birthRate
设置为0,以便停止发射。
您可以使用类似dispatch_after()
的内容来执行此延迟。
我做了类似的事情,并且像这样解决了。以下将创建一个快速爆发的粒子。下次想要粒子发射时,将“云”的birthRate更改回1.
CAEmitterCell *dustCell = [[CAEmitterCell alloc] init];
[dustCell setBirthRate:7000];
[dustCell setLifetime:3.5];
// Various configurations for the appearance...
// This is the only cell with configured scale,
// color, content, emissionLongitude, etc...
CAEmitterCell *dustCloud = [CAEmitterCell emitterCell];
[dustCloud setBirthRate:1.0]; // Create one cloud every second
[dustCloud setLifetime:0.06]; // Emit dustCells for 0.06 seconds
[dustCloud setEmitterCells:[NSArray arrayWithObject:dustCell]];
[dustCloud setName:@"cloud"]; // Use this name to change the birthRate later
[dustEmitter setEmitterPosition:myPositionForDustEmitter];
[rightDustEmitter setEmitterCells:[NSArray arrayWithObject:dustCloud]];
// After one burst, change the birth rate of the cloud to 0
// so that there is only one burst per side.
double delayInSeconds = 0.5; // One cloud will have been created by now, but not two
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void) {
// For some reason, setting the birthRate of the "cloud" to 0
// has a strange side effect that when you set it back to 1 all
// the missed emissions seems to happen at once during the first
// emission and then it goes back to only emitting once per
// second. (Thanks D33 for pointing this out).
// By instead changing the birthRate of the "dust" particle
// to 0 and then back to (in my case) 7000 gives the visual
// effect that I'm expecting. I'm not sure why it works
// this way but at least this works for me...
// NOTE: This is only relevant in case you want to re-use
// the emitters for a second emission later on by setting
// the birthRate up to a non-zero value.
[dustEmitter setValue:[NSNumber numberWithFloat:0.0]
forKeyPath:@"emitterCells.cloud.emitterCells.dust.birthRate"];
});
答案 1 :(得分:6)
感谢foundrys出色的回答over here我解决了一个与此非常相似的问题。它不涉及隐藏任何视图。简而言之,它是这样的:
像往常一样设置发射器,命名发射器单元并给它们一个出生值为零:
-(void) setUpEmission {
# ...
# snip lots of config
# ...
[emitterCell1 setBirthrate:0];
[emitterCell1 setName:@"emitter1"];
[emitterCell2 setBirthrate:0];
[emitterCell2 setName:@"emitter2"];
emitterLayer.emitterCells = @[emitterCell1, emitterCell2];
[self.view.layer addSublayer:emitterLayer];
}
然后创建一个启动方法,在短时间后自动关闭发射,并使用停止方法:
-(void) startEmission {
[emitterLayer setValue:@600 forKeyPath:@"emitterCells.emitter1.birthRate"];
[emitterLayer setValue:@250 forKeyPath:@"emitterCells.emitter2.birthRate"];
[NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(stopEmission) userInfo:nil repeats:NO];
}
-(void) stopEmission {
[emitterLayer setValue:@0 forKeyPath:@"emitterCells.emitter1.birthRate"];
[emitterLayer setValue:@0 forKeyPath:@"emitterCells.emitter2.birthRate"];
}
在这个例子中,我将出生率设置为600和250.定时器在0.2秒后关闭发射,但使用你认为合适的任何东西。
如果Apple实施了启动/停止方法,那么最佳解决方案就是如此,但我发现这是一个令人满意的解决方案。
答案 2 :(得分:5)
我也在寻找解决方案并找到了article。
查看此Gist的五彩纸屑粒子及其Stop Emitting
方法。
它的作用是:
confettiEmitter.birthRate = 0.0;
停止发出新粒子。希望它可以提供帮助。
答案 3 :(得分:1)
CAEmitter.birthRate
是可动画的。假设您已在视图中添加了一些CAEmitterLayer
s,您可以执行此操作来设置出生率的衰减动画,然后在几秒钟后重新启动:
- (void) startConfetti{
for (CALayer *emitterLayer in self.layer.sublayers) {
if ([emitterLayer isKindOfClass: [CAEmitterLayer class]]) {
((CAEmitterLayer *)emitterLayer).beginTime = CACurrentMediaTime();
((CAEmitterLayer *)emitterLayer).birthRate = 6;
// Decay over time
[((CAEmitterLayer *)emitterLayer) removeAllAnimations];
[CATransaction begin];
CABasicAnimation *birthRateAnim = [CABasicAnimation animationWithKeyPath:@"birthRate"];
birthRateAnim.duration = 5.0f;
birthRateAnim.fromValue = [NSNumber numberWithFloat:((CAEmitterLayer *)emitterLayer).birthRate];
birthRateAnim.toValue = [NSNumber numberWithFloat:0.0f];
birthRateAnim.repeatCount = 0;
birthRateAnim.autoreverses = NO;
birthRateAnim.fillMode = kCAFillModeForwards;
[((CAEmitterLayer *)emitterLayer) addAnimation:birthRateAnim forKey:@"finishOff"];
[CATransaction setCompletionBlock:^{
((CAEmitterLayer *)emitterLayer).birthRate = 0.f;
[self performSelector:@selector(startConfetti) withObject:nil afterDelay:10];
}];
[CATransaction commit];
}
}
}
答案 4 :(得分:0)
好的,最后,经过数小时的测试并尝试了不同的风格(初始化,删除,配置发射器),我想出了最终结果...... 实际上它让我非常沮丧...
---这是不可能的!---
即使我每次需要它时都会创建发射器及其粒子,如果我只设置一个粒子来发射,它会给我大部分时间一个粒子......但它不是100%,有时它只发出三个粒子,或者两个......这是随机的。这非常糟糕。因为它是视觉效果...... :(
无论哪种方式,如果有人提示如何解决这个问题,请告诉我......
答案 5 :(得分:0)
您是否考虑过利用CALayers的动画属性?
func setEmitterProperties() {
backgroundColor = UIColor.clearColor().CGColor
birthRate = kStandardBirthRate
emitterShape = kCAEmitterLayerLine
emitterCells = [typeOneCell, typeTwoCell, typeOneCell]
preservesDepth = false
let birthRateDecayAnimation = CABasicAnimation()
birthRateDecayAnimation.removedOnCompletion = true
birthRateDecayAnimation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
birthRateDecayAnimation.duration = CFTimeInterval(kStandardAnimationDuration)
birthRateDecayAnimation.fromValue = NSNumber(float: birthRate)
birthRateDecayAnimation.toValue = NSNumber(float: 0)
birthRateDecayAnimation.keyPath = kBirthRateDecayAnimationKey
birthRateDecayAnimation.delegate = self
}
如果您不想这样做,委托属性也可能是零 完成的任何事情,如 animationDidStop:finished:
常数kBirthRateDecayAnimationKey& kStandardAnimationDuration使用我的约定,而不是Apple的。