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
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
rocket.addAnimation(anim, forKey: "group")