Logo for tanaschita.com

Creating a particles snow effect with SpriteKit and SwiftUI

In this Christmas special, we'll have some fun with snow particles.

20 Dec 2021 · 5 min read

Apple's SpriteKit framework is mostly used to build 2D games since it supports drawing, particles, physics effects, animations, collision detection and a lot more.

In this Christmas special article, we are going to take a look into SpriteKit's particle emitter to create a snow effect and combine it with a SwiftUI view.

iOS Simulator showing a snowman with snow particles
Using SpriteKit and SwiftUI to create add a snow particles effect over an image.

Let's dive in.

Adding a SpriteKit particle file

It is really easy to create a snow effect in SpriteKit with the particle emitter editor. As a first step, we will add a new particle emitter to our project.

  1. Create a new file with File > New > File in Xcode.
  2. Select Resource > SpriteKit Particle File.
  3. Select snow from the preinstalled particle emitter textures.
Xcode's particles editor
Xcode's particles editor

With Xcode's build-in particles editor, we can now experiment with some properties to change the snow effect to the way we want it.

Creating a SpriteKit scene

Each onscreen element in SpriteKit is represented by a node. A SpriteKit scene is the root node in a tree of those nodes.

So we can set up a SpriteKit scene by adding nodes to it. This might look as follows:

class SnowScene: SKScene {
let snowEmitterNode = SKEmitterNode(fileNamed: "snow.sks")
override func didMove(to view: SKView) {
guard let snowEmitterNode = snowEmitterNode else { return }
snowEmitterNode.particleSize = CGSize(width: 50, height: 50)
snowEmitterNode.particleLifetime = 2
snowEmitterNode.particleLifetimeRange = 6
addChild(snowEmitterNode)
}
override func didChangeSize(_ oldSize: CGSize) {
guard let snowEmitterNode = snowEmitterNode else { return }
snowEmitterNode.particlePosition = CGPoint(x: size.width/2, y: size.height)
snowEmitterNode.particlePositionRange = CGVector(dx: size.width, dy: size.height)
}
}

As we can see above, we create a SKEmitterNode by initializing it with the particles file name. We add the node with addChild() to the scene in the didMove(to:) method which is called when the scene is presented by a view.

All particle properties we saw in the editor can also be configured programmatically. For example, we set the particleLifetime to be 2 seconds but also to add a random variance about the lifetime of each particle up to 6 seconds with particleLifetimeRange. This setting creates a more indepth effect of the snow since some particles disappear before reaching the bottom.

We also override the didChangeSize(_:) method to position the particles. If you want to learn more about sizing scenes and nodes, check out this quick tip on how to position and size SpriteKit nodes

Adding the scene to a SwiftUI view

Now, we can add the created scene to SwiftUI views by using SpriteView.

struct ContentView: View {
var scene: SKScene {
let scene = SnowScene()
scene.scaleMode = .resizeFill
scene.backgroundColor = .clear
return scene
}
var body: some View {
ZStack {
Image("background")
.resizable()
.aspectRatio(contentMode: .fill)
.ignoresSafeArea()
SpriteView(scene: scene, options: [.allowsTransparency])
.ignoresSafeArea()
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
}

By setting the scene's backgroundColor to .clear and configuring the SpriteView with the .allowsTransparency option, we have now positioned the snow effect over a SwiftUI view.

Image of books
Further reading: SwiftUI by Example
For further reading, check out the SwiftUI by Example book by Paul Hudson. It guides you through dozens of common coding problems with hands-on solutions.

Newsletter

Receive a monthly newsletter about the latest articles and tips.

Image of a reading marmot

Related tags

Written by

Articles with related topics

Latest articles and tips