SpriteKit
Build 2D games and interactive animations for iOS 26+ using SpriteKit and Swift 6.3. Covers scene lifecycle, node hierarchy, actions, physics, particles, camera, touch handling, and SwiftUI integration.
Contents
- Scene Setup
- Nodes and Sprites
- Actions and Animation
- Physics
- Touch Handling
- Camera
- Particle Effects
- SwiftUI Integration
- Common Mistakes
- Review Checklist
- References
Scene Setup
SpriteKit renders content through SKView, which presents an SKScene -- the
root node of a tree that the framework animates and renders each frame.
Creating a Scene
Subclass SKScene and override lifecycle methods. The coordinate system
origin is at the bottom-left by default.
Presenting a Scene (UIKit)
Scale Modes
Use .resizeFill when the scene should adapt to view size changes (rotation,
multitasking). Use .aspectFill for fixed-design game scenes. .aspectFit
letterboxes; .fill stretches and may distort.
Frame Cycle
Each frame follows this order:
update(_:)-- game logic- Evaluate actions
didEvaluateActions()-- post-action logic- Simulate physics
didSimulatePhysics()-- post-physics adjustments- Apply constraints
didApplyConstraints()didFinishUpdate()-- final adjustments before rendering
Override only the callbacks where work is needed.
Nodes and Sprites
Use SKNode (without a visual) as an invisible container or layout group.
Child nodes inherit parent position, scale, rotation, alpha, and speed.
SKSpriteNode is the primary visual node.
Common Node Types
Creating Sprites
Drawing Order
Set ignoresSiblingOrder = true on SKView for better performance; SpriteKit
then uses zPosition to determine order. Without it, nodes draw in tree order.
Naming and Searching
Assign name to find nodes without instance variables. Use childNode(withName:),
enumerateChildNodes(withName:using:), or subscript. Patterns: // searches
the entire tree, * matches any characters, .. refers to the parent.
Actions and Animation
SKAction objects define changes applied to nodes over time. Actions are
immutable and reusable. Run with node.run(_:).
Basic Actions
Combining Actions
Texture Animation
Control the speed curve with timingMode (.linear, .easeIn, .easeOut,
.easeInEaseOut). Assign keys to actions for later access:
Physics
SpriteKit provides a built-in 2D physics engine. The scene's physicsWorld
manages gravity and collision detection.
Adding Physics Bodies
Category and Contact Masks
Use bit masks to control collisions and contact callbacks:
categoryBitMask identifies the body. collisionBitMask controls physics
response (bouncing). contactTestBitMask triggers didBegin/didEnd.
Contact Detection
Implement SKPhysicsContactDelegate and set physicsWorld.contactDelegate = self
in didMove(to:):
Contact callbacks run during physics simulation. Make queuePlayerHit() set a
flag or append an event, then apply node/body/world mutations in update(_:).
Forces and Impulses
Use .applyImpulse for jumps and projectile launches. Configure gravity with
physicsWorld.gravity = CGVector(dx: 0, dy: -9.8) and per-body with
affectedByGravity.
Touch Handling
SKScene inherits from UIResponder. Override touchesBegan, touchesMoved,
touchesEnded on the scene. Use nodes(at:) to hit-test.
For node-level touch handling, subclass the node and set
isUserInteractionEnabled = true. That node then receives touches directly
instead of the scene.
Camera
SKCameraNode controls the visible portion of the scene. Add it as a child
and assign to scene.camera.
Following a Character
Update the camera position in didSimulatePhysics() or use constraints:
Camera Zoom and HUD
Scale the camera node inversely: setScale(0.5) zooms in 2x, setScale(2.0)
zooms out 2x. Nodes added as children of the camera stay fixed on screen
(HUD elements):
Particle Effects
SKEmitterNode generates particle effects. Design emitters in Xcode's
SpriteKit Particle File editor (.sks) or configure in code.
One-Shot Emitters
Set numParticlesToEmit for finite effects and remove after completion:
Set targetNode to the scene so particles stay in world space when the
emitter moves: emitter.targetNode = self.
SwiftUI Integration
SpriteView embeds a SpriteKit scene in SwiftUI.
SpriteView Options
Pass options: [.allowsTransparency] for transparent backgrounds,
.shouldCullNonVisibleNodes for offscreen culling, or .ignoresSiblingOrder
for zPosition-based draw order. Use debugOptions: [.showsFPS, .showsNodeCount]
during development.
Communicating Between SwiftUI and the Scene
Pass data through a shared @Observable object. Store the scene in @State
to avoid re-creation on view re-renders:
Common Mistakes
Creating a new scene on every SwiftUI re-render
Adding a child node that already has a parent
A node can only have one parent. Remove from the current parent first or create a separate instance. Adding a node that already has a parent crashes.
Forgetting to set contactTestBitMask
Using SKShapeNode for performance-critical rendering
SKShapeNode uses a separate draw call per instance. Prefer SKSpriteNode
with a texture for repeated elements to enable batched rendering.
Not removing nodes that leave the screen
Setting physicsWorld.contactDelegate too late
Set physicsWorld.contactDelegate = self in didMove(to:), not in
update(_:) or after a delay.
Review Checklist
- Scene subclass overrides
didMove(to:)for setup, notinit -
scaleModechosen appropriately for the game's design -
ignoresSiblingOrderset totrueonSKViewfor performance -
zPositionused consistently whenignoresSiblingOrderis enabled - Physics
contactDelegateset indidMove(to:) - Category, collision, and contact bit masks configured correctly
-
contactTestBitMaskset for any pair needingdidBegin/didEndcallbacks - Contact callbacks queue changes instead of mutating the physics world directly
- Static bodies use
isDynamic = false -
SKShapeNodeavoided in performance-critical paths;SKSpriteNodepreferred - Actions that move nodes offscreen include
.removeFromParent()in sequence - One-shot emitters remove themselves after particle lifetime expires
- Emitter
targetNodeset when particles should stay in world space - Scene stored in
@Statewhen used withSpriteViewin SwiftUI - Texture atlases used for related sprites to reduce draw calls
-
update(_:)uses delta time for frame-rate-independent movement - Nodes removed from parent before being re-added elsewhere
References
- See references/spritekit-patterns.md [blocked] for tile maps, texture atlases, shaders, scene transitions, game loop patterns, audio, and SceneKit embedding.
- SpriteKit documentation
- SKScene
- SKSpriteNode
- SKAction
- SKPhysicsBody
- SKEmitterNode
- SKCameraNode
- SpriteView
- SKTileMapNode


