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