12

私は CAEmitterLayer をいじっていますが、現在いくつかの問題に直面しています :(

たとえば、ヒットや爆発のような短いパーティクル効果が必要です (したがって、この場所に小さな UIView があります)。どうすればいいですか?

1、私にはアイデアがありました - パーティクルでエミッターレイヤーを作成し、lifeTime を 0 に設定します。必要なときは、たとえば lifeTime を 1 に設定し、しばらくしてから 0 に戻すことができます。 - しかし、何もしていません。 :(

2、2番目のアイデアは、必要なたびに[CAEmitterLayerレイヤー]を作成し、レイヤーサブレイヤーとして追加することでした。しかし、たとえば10回繰り返すとどうなるか考えています.10のサブレイヤーがあり、1つのアクティブと9つの「デッド」がありますか? 一般的に放出を停止するには?しばらくしてからライフタイムを0に設定し、他のセレクターをremoveFromSuperlayerに設定するためにperformSelectorを持っています...しかし、それは私が望むほどきれいではありません:(別の「適切な」方法はありますか?

サブレイヤーが多すぎるのは、別の問題に関連していると思います... パーティクルを 1 つだけ放出したいのです。そして、私がそれを行うと、それは機能します。しかし、3 つの粒子を放出することもあれば、2 つの粒子を放出することもあります。エミッターを停止しないと、毎回正しい数のパーティクルが与えられます...

質問は…</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

これを行うには、すべてを1回構成し(毎回新しいエミッタセルを追加しないでください)、birthRateを0に設定します(パーティクルは作成されません)。次に、パーティクルを作成するときに、作成するbirthRate1秒あたりのパーティクル数にを設定できます。一定時間後birthRate、放出が停止するように0に戻します。dispatch_after()この遅延を行うためにのようなものを使用できます。


しばらく前に似たようなことをして、このように解決しました。以下は、パーティクルの1つのクイックバーストを作成します。次にパーティクルを放出するときは、「クラウド」の出生率を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 に答える
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. animationDidStop:finished:のように、完了時に何もしたくない場合は、delegate プロパティを nil にすることもできます。

  2. 定数 kBirthRateDecayAnimationKey と kStandardAnimationDuration は、Apple のものではなく、私の規則を使用します。

于 2015-08-01T01:51:36.883 に答える
0

OK、最終的に、何時間ものテストとさまざまなスタイル (エミッターの初期化、削除、構成) の試行の後、最終結果にたどり着きました...そして、実際には非常に動揺しています...

- -それは不可能! - -

必要なたびにエミッターとそのパーティクルを作成する場合でも、1 つのパーティクルのみを放出するように設定すると、ほとんどの場合 1 つのパーティクルが得られます... しかし、100% ではなく、3 つまたは 2 つのパーティクルしか放出しないこともあります。 .. ランダムです。そして、それは非常に悪いです。視覚効果なので... :(

いずれにせよ、誰かがこれを解決する方法を知っているなら、私に知らせてください...

于 2012-06-10T09:59:04.217 に答える