No history yet

Scene Architecture

The Stage and the Play

In SpriteKit, your game lives inside an SKView. Think of this as the physical stage in a theater. It's a standard iOS view that you place in your app's window, and its only job is to present your game's content. It handles the low-level rendering work for you.

The play itself, with all its characters and scenery, is an SKScene. The SKView presents an SKScene. You can have multiple scenes in your game, like a main menu scene, a gameplay scene, and a game-over scene. You transition between these scenes, but the SKView remains the constant stage.

// In your ViewController
import SpriteKit

if let view = self.view as! SKView? {
    // Create the scene
    let scene = GameScene(size: view.bounds.size)

    // Present the scene
    view.presentScene(scene)
}

Where Am I?

Unlike UIKit, where the origin point (0, 0) is at the top-left corner of the screen, SpriteKit places its origin at the bottom-left. This is more traditional for game development and aligns with the Cartesian coordinate system you might remember from math class. The positive y-axis goes up, and the positive x-axis goes to the right.

This means if you place a character at position (100, 50), it will be 100 points to the right of the left edge and 50 points up from the bottom edge of the scene.

A Family of Nodes

Everything you see in a SpriteKit scene is an SKNode. This is the basic building block for all content. The SKScene itself is the root node of a structure called the node tree or scene graph.

You add other nodes as children of the scene or as children of other nodes. For example, you might add a player node to the scene. Then, you might add a weapon node as a child of the player. This creates a parent-child hierarchy.

A child node's position is always relative to its parent. If a parent is at (100, 100) and its child is at (10, 0), the child's actual position in the scene is (110, 100).

The Game Loop

Games aren't static. They're constantly changing—characters move, scores update, timers count down. This is managed by the game loop, a process that runs many times per second. In each pass, the game updates its state and redraws the screen. SpriteKit handles the redrawing, but you're responsible for updating the state.

The primary entry point for your game loop logic is the update() method in your SKScene. This method is called once per frame, just before the scene is rendered. It's the perfect place to update positions, check for collisions, and handle user input.

class GameScene: SKScene {
    private var lastUpdateTime : TimeInterval = 0

    override func update(_ currentTime: TimeInterval) {
        // Called before each frame is rendered
        if (self.lastUpdateTime == 0) {
            self.lastUpdateTime = currentTime
        }

        // Calculate time since last update
        let dt = currentTime - self.lastUpdateTime

        // Update game objects here using dt...

        self.lastUpdateTime = currentTime
    }
}

Besides update(), SKScene has other important lifecycle methods. didMove(to:) is called when the scene is first presented by a view, making it the ideal spot for initial setup—creating nodes, setting up physics, etc. Conversely, willMove(from:) is called just before the scene is removed, allowing you to perform cleanup.

Handling Different Screens

Apple devices come in all shapes and sizes. A scene that looks perfect on an iPhone might look stretched or have empty bars on an iPad. SpriteKit provides a scaleMode property on SKScene to manage this automatically.

Scale ModeDescription
.fillStretches the scene to fill the view, potentially distorting aspect ratio.
.aspectFillScales the scene to fill the view while preserving aspect ratio. Some parts of the scene may be cropped.
.aspectFitScales the scene to fit within the view while preserving aspect ratio. This may result in letterboxing (black bars).
.resizeFillResizes the scene to match the view's dimensions, not preserving aspect ratio.

For most games, .aspectFill is the best choice. It ensures your game fills the entire screen without distortion. You just need to design your scene with the assumption that the edges might be clipped on certain devices. Keep important UI elements and gameplay action away from the extreme top, bottom, and sides.

With this architectural foundation, you can build scenes that are organized, efficient, and adaptable to any screen size.