Reputation: 1128
I am trying to animate an explosion with CAEmitterLayer
and a couple of CAEmitterCell
. This should happen after a short delay after user sees a view. I start my animation in viewDidAppear
.
Particle animation itself works fine, but as in this question Initial particles from CAEmitterLayer don't start at emitterPosition unless I set emitterLayer.beginTime = CACurrentMediaTime()
animation appears to user as one that has been running for some time.
Now to actually achieve an explosion I have to stop emitting particles at some point. I try to use this code to setup CABasicAnimation
which would stop emitter after some time:
// emitter layer is reused (remove all animations, remove all cells, remove from superlayer)
... // emitter layer setup in a function "explode" which is called from viewDidAppear
emitterLayer.beginTime = CACurrentMediaTime()
let birthRateAnimation = CABasicAnimation(keyPath: "birthRate")
birthRateAnimation.toValue = 0
birthRateAnimation.timingFunction = CAMediaTimingFunction.init(name:kCAMediaTimingFunctionEaseOut)
birthRateAnimation.beginTime = CACurrentMediaTime() + 1
birthRateAnimation.duration = 5
birthRateAnimation.delegate = self // (self is view controller)
birthRateAnimation.setValue("expl", forKey: "animName")
emitterLayer.add(birthRateAnimation, forKey: "birthRateAnimation")
self.view.layer.addSublayer(emitterLayer)
So now with this code birthRateAnimation
is not actually triggered. I have logs in animationDidStop
and animationDidStart
which don't print anything.
Now, if I call explode
function on button tap I see no particle animation at all, but in logs I see "animation start" / "animation stop" messages.
Any idea why?
Upvotes: 2
Views: 1339
Reputation: 8164
Late to the party, but I ran into the very same thing and the solution is to set beginTime
of your emitter to CACurrentMediaTime()
, e.g.:
let emitter = makeAwesomeEmitter()
emitter.beginTime = CACurrentMediaTime()
let emitterAnimation = makeAwesomeEmitterBirthRateAnimation()
emitterAnimation.beginTime = 1.0 // 1 sec delay
emitter.add(emitterAnimation, forKey: nil)
myView.layer.addSublayer(emitter)
Rationale is that the emitter pre-generates particles to imitate it running already for a while. See also this SO question which brought me to the solution.
Upvotes: 1
Reputation: 546
I found two problems that kept the animation from working correctly.
birthRate
, but CAEmitterLayer
does not have a birthRate
property; CAEmitterCell
does, though. Give your CAEmitterCell
a name and change CABasicAnimation(keyPath: "birthRate")
to CABasicAnimation(keyPath: "emitterCells.cellName.birthRate")
CACurrentMediaTime() + 1.0
does not do what you want, because the emitter layer has its own time scale. Changing that to emitterLayer.convertTime(CACurrentMediaTime(), from: nil) + 1.0
does what you want.Upvotes: 3