CAReplicatorLayer

Episode #196 | 15 minutes | published on 11/06/2015 | Uses tvOS-9.0
Subscribers Only
In this episode we take our missile animation from last time and update it to use CAAnimations. Using these animations we can add a wiggle, along with a small oscillating rotation to give a little life to the missile. Then we utilize CAReplicatorLayer to have them fan out and fire in slightly different directions.

Episode Links

Creating our Rocket Layer

let rocketImage = UIImage(named: "missile")!
let rocket = CALayer()
let size = rocketImage.size
rocket.contents = rocketImage.CGImage
rocket.frame = CGRect(x: -size.width, y: 100, width: size.width, height: size.height)

We're starting it off-screen so we can animate it in smoothly.

Animating it across the screen

To do this we'll use a transform animation and translate the X position to a spot far off the right side of the screen.

let travel = CABasicAnimation(keyPath: "transform.translation.x")
travel.duration = 1.5
travel.fromValue = 0
travel.toValue = view.frame.size.width + 400
travel.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)

Here we use ease in as the timing function because we don't want it to slow down at the end.

Adding a little wiggle

To make the rocket wiggle in the Y direction, we'll do another translation, but this time we'll have it automatically reverse direction, using a smooth ease-in/ease-out curve.

let wiggle = CABasicAnimation(keyPath: "transform.translation.y")
wiggle.autoreverses = true
wiggle.fromValue = 0
wiggle.toValue = -94
wiggle.duration = 0.35
wiggle.repeatCount = Float.infinity
wiggle.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

Rotating synchronized with the wiggle animating

To have our rocket seem to point in the direction of the wiggle we can rotate the layer slightly. We'll copy the duration, & repeat settings from wiggle and animate back & forth from a small angle.

We'll also have to make sure that we start our layer with the right angle so the animation is consistent.

let angle = CGFloat(M_PI / 16.0)

rocket.transform = CATransform3DMakeRotation(-angle, 0, 0, 1.0)

let wiggleRotation = CABasicAnimation(keyPath: "transform.rotation")
wiggleRotation.beginTime = 0.08
wiggleRotation.duration = wiggle.duration
wiggleRotation.fromValue = -angle
wiggleRotation.toValue = angle
wiggleRotation.autoreverses = true
wiggleRotation.repeatCount = Float.infinity

The beginTime is set to delay this animation slightly so it matches up visually with the wiggle animation. This number should be tweaked until it looks right.

Replicating the rocket

Finally, we can make multiple copies of the rocket layer & animation by using CAReplicatorLayer. We'll set a small delay on each instance so they don't all come in at once, and we'll add a rotation so they fan out and travel in different directions.

let replicator = CAReplicatorLayer()
replicator.instanceCount = 10
replicator.instanceDelay = 0.1
replicator.instanceTransform = CATransform3DMakeTranslation(0, 90, 0)
replicator.instanceTransform = CATransform3DRotate(replicator.instanceTransform, CGFloat(M_PI / 80.0), 0, 0, 1.0)

Finalizing the animation

Now we just need to add these animations to a group, and add our replicator to our view's layer tree.

let anim = CAAnimationGroup()
anim.animations = [ travel, wiggle, wiggleRotation ]
anim.duration = travel.duration
anim.fillMode = kCAFillModeForwards
anim.removedOnCompletion = false

view.layer.addSublayer(replicator)

rocket.addAnimation(anim, forKey: "group")

replicator.addSublayer(rocket)
blog comments powered by Disqus