DVD animation in Swift with SpriteKit

Alex Persian
3 min readJun 1, 2019

--

This a quick one for you. Remember the screensaver that would to show up on your old CRT tv when the DVD player went to sleep? I loved that, didn’t you? There was always a shred of hope that you’d get to see it perfectly hit the corner. Let’s recreate that using SpriteKit. As always, the repo link with a complete Playground will be available at the end of this article.

To start out we will need to create some basic structure for the scene. This will consist of an SKView, an SKNode, and an SKScene. You can think of these three pieces as the stage, the actor, and the director respectively. Let’s go ahead and create this structure now.

With this we have created the base of our scene. If you build and run this though you’ll quickly notice that there’s two major things missing: color and motion. Let’s fix that now by introducing a bit of logic to our director. Create a new file and make it a subclass of SKScene. We’ll call it DVDScene. Important: Make sure to declare this class as public so that it can be accessed from our main playground file since these two files live within separate modules.

Here we’ve created a basic subclass of SKScene and overriden the init to allow us to pass in an SKNode directly. Since we know strictly how we want this node and scene to interact this let’s us simplify some logic further along. Now replace lines 10 and 11 within the main playground file with:

let mainScene = DVDScene(node: dvdNode, size: view.frame.size)

Simple as that. The scene in the playground should look the same as before. We still don’t have any color or motion though. Let’s get to work on that. For color we want it to be random, but ensure that each one chosen is vibrant to match the original screensaver style. Add this extension to UIColor:

This will give us a nice, bright set of colors to work with without having to define them all ourselves manually. Now, in order for our node to start changing its color we can’t just call node.tintColor like we would in the UIKit world. Instead we need to create what’s called an SKAction and tell it to perform a colorize action on the node. SKActions are one of the main ways you’ll interact with and manipulate nodes. Let’s write that now and set it so that it’s triggered when the scene starts.

Alright, cool! Now we have a logo that changes colors every time you run the playground. But we still don’t have the last piece of our puzzle; the motion. For that we will need to bring in some transforms. Thankfully there isn’t any sort of witchcraft or fancy frameworks we need to leverage to accomplish movement. Nodes can be manipulated just like normal views through the use of CoreGraphics transforms. Wonderful! Let’s create one now.

private var moveTransform = CGAffineTransform(translationX: 1.0, y: 1.0)

Great. With a transform we can change the position of the node by a set amount. That set movement will allow us to get the animation we desire once we combine it with the update function. It is called by the system once per frame, so we can use it as a sort of clock to make incremental movements of our node. See below for the full function.

So what’s happening here? First we collect the current frame of the node to figure out where it is within the parent frame. Then we sequentially check to see if the node’s frame has intersected any of the edges of the parent’s frame. If so, we reverse either the horizontal or vertical directions depending on what edge was hit.

And there you have it! With this final function block we should now see a fully operational DVD logo screensaver. Play around with the sizing and speed of the logo to experiment. See if you can catch it hitting one of the corners perfectly. Whoooo nostalgia!

Psst: Why do we have to run changeColor in each of the if blocks instead of just writing it once by the dvdNode.position call? Try it to find out 🕺

If you have any questions, notice any mistakes, or think any piece should be clarified further let me know in the comments below. Thanks for reading!

--

--