12

我正在玩 CAEmitterLayer,现在我遇到了一些问题:(

例如,我需要一个短粒子效果——比如撞击或爆炸——在一个地方(所以我在这个地方有一个小的 UIView)。我该怎么做?

1,我有一个想法——用它的粒子创建emitterLayer并将lifeTime设置为0。例如,当我需要它时,我将lifeTime设置为1,过了一会儿我可以将它设置回0。 - 但它没有做任何事情:(

2、第二个想法是每次需要时都创建[CAEmitterLayer layer]并将其添加为layers sublayer。但是我在想当我重复它十次时会发生什么……我有 10 个子层,其中一个活跃,9 个“死”?一般如何停止发射?一段时间后我有 performSelector 将生命周期设置为 0 和其他具有更长间隔的选择器来 removeFromSuperlayer ......但它并不像我想要的那样漂亮:( 还有另一种“正确”的方式吗?

我认为子层太多与我的另一个问题有关……我只想发射一个粒子。当我这样做时,它会起作用。但有时它会发出三个粒子,有时是两个……这让我很生气。当我不停止发射器时,它每次都会给出正确数量的粒子......

所以问题...</p>

如何在短时间内发射粒子。如何使用它们 - 比如停止,从父层移除,......如何发射精确数量的粒子

编辑:

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;
});

更改为@David Rö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"];
});
4

6 回答 6

11

您可以通过一次配置所有内容(不要每次都添加新的发射器单元)并将其设置birthRate为 0(不会创建任何粒子)来做到这一点。然后,当您要创建粒子时,您可以将 设置为birthRate每秒要创建的粒子数。一段时间后,您将birthRateback 设置为 0,以便发射停止。你可以使用类似的东西dispatch_after()来做这个延迟。


我不久前做了类似的事情并像这样解决了它。以下将创建一个快速的粒子爆发。下次您希望粒子发射时,将“云”的出生率更改回 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"];
});
于 2012-06-07T11:14:24.567 回答
6

感谢铸造厂在这里的出色回答,我解决了一个与此非常相似的问题。它不涉及隐藏任何视图。简而言之,它是这样的:

像往常一样设置您的发射器,命名发射器单元并将它们的出生率值设为零:

-(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];
}

然后创建一个在片刻后自动关闭发射的 start 方法和一个 stop 方法:

-(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 实施了启动/停止方法,但除此之外,我发现这是一个令人满意的解决方案。

于 2013-10-30T09:20:07.243 回答
5

我也在寻找解决方案并找到了这篇文章

看看这个Gist的五彩纸屑粒子及其Stop Emitting方法。

它的作用是:

  1. 将粒子视图添加到您的显示视图。
  2. 让粒子随心所欲地运行。
  3. 停止新粒子的发射confettiEmitter.birthRate = 0.0;
  4. 等待几秒钟。
  5. 删除粒子视图。

希望它可以提供帮助。

于 2012-10-01T14:16:56.423 回答
2

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];
    }
  }
}
于 2017-08-13T12:15:19.190 回答
0

好的,最后,经过数小时的测试和尝试不同的风格(初始化、删除、配置发射器),我得出了最终的结果......实际上这让我非常沮丧......

- -这不可能! - -

即使我每次需要它时都创建发射器及其粒子,如果我只设置一个粒子发射,它在大多数情况下都会给我一个粒子......但它不是 100%,有时它只发射三个或两个粒子。 .. 这是随机的。这是非常糟糕的。因为它是视觉效果... :(

无论哪种方式,如果有人有提示如何解决这个问题,请告诉我......

于 2012-06-10T09:59:04.217 回答
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

  }
  1. 如果您不想在完成时执行任何操作,委托属性也可以为 nil,如animationDidStop:finished:

  2. 常量 kBirthRateDecayAnimationKey 和 kStandardAnimationDuration 使用我的约定,而不是 Apple 的。

于 2015-08-01T01:51:36.883 回答