axiom-spritekit-ref

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SpriteKit API Reference

SpriteKit API参考

Complete API reference for SpriteKit organized by category.
按类别组织的SpriteKit完整API参考。

When to Use This Reference

何时使用本参考文档

Use this reference when:
  • Looking up specific SpriteKit API signatures or properties
  • Checking which node types are available and their performance characteristics
  • Finding the right physics body creation method
  • Browsing the complete action catalog
  • Configuring SKView, scale modes, or transitions
  • Setting up particle emitter properties
  • Working with SKRenderer or SKShader
在以下场景使用本参考文档:
  • 查找特定SpriteKit API的签名或属性
  • 查看可用的节点类型及其性能特征
  • 寻找合适的物理体创建方法
  • 浏览完整的动作目录
  • 配置SKView、缩放模式或转场效果
  • 设置粒子发射器属性
  • 使用SKRenderer或SKShader

Part 1: Node Hierarchy

第一部分:节点层级

All Node Types

所有节点类型

NodePurposeBatches?Performance Notes
SKNode
Container, groupingN/AZero rendering cost
SKSpriteNode
Textured spritesYes (same atlas)Primary gameplay node
SKShapeNode
Vector pathsNo1 draw call each — avoid in gameplay
SKLabelNode
Text renderingNo1 draw call each
SKEmitterNode
Particle systemsN/AGPU-bound, limit birth rate
SKCameraNode
Viewport controlN/AAttach HUD as children
SKEffectNode
Core Image filtersNoExpensive — cache with
shouldRasterize
SKCropNode
MaskingNoMask + content = 2+ draw calls
SKTileMapNode
Tile-based mapsYes (same tileset)Efficient for large maps
SKVideoNode
Video playbackNoUses AVPlayer
SK3DNode
SceneKit contentNoRenders SceneKit scene
SKReferenceNode
Reusable .sks filesN/ALoads archive at runtime
SKLightNode
Per-pixel lightingN/ALimits: 8 lights per scene
SKFieldNode
Physics fieldsN/AGravity, electric, magnetic, etc.
SKAudioNode
Positional audioN/AUses AVAudioEngine
SKTransformNode
3D rotation wrapperN/AxRotation, yRotation for perspective
节点用途支持批处理?性能说明
SKNode
容器、分组N/A无渲染开销
SKSpriteNode
带纹理的精灵是(同一图集)主要游戏玩法节点
SKShapeNode
矢量路径每个节点1次绘制调用——游戏玩法中避免使用
SKLabelNode
文本渲染每个节点1次绘制调用
SKEmitterNode
粒子系统N/A受GPU限制,限制生成速率
SKCameraNode
视口控制N/A将HUD作为子节点附加
SKEffectNode
Core Image滤镜开销大——使用
shouldRasterize
缓存
SKCropNode
遮罩遮罩+内容=2次以上绘制调用
SKTileMapNode
瓦片地图是(同一瓦片集)大地图高效渲染
SKVideoNode
视频播放使用AVPlayer
SK3DNode
SceneKit内容渲染SceneKit场景
SKReferenceNode
可复用的.sks文件N/A运行时加载归档文件
SKLightNode
逐像素光照N/A限制:每个场景最多8盏灯
SKFieldNode
物理场N/A重力、电场、磁场等
SKAudioNode
3D位置音频N/A使用AVAudioEngine
SKTransformNode
3D旋转包装器N/AxRotation、yRotation用于透视效果

SKSpriteNode Properties

SKSpriteNode属性

swift
// Creation
SKSpriteNode(imageNamed: "player")           // From asset catalog
SKSpriteNode(texture: texture)                // From SKTexture
SKSpriteNode(texture: texture, size: size)    // Custom size
SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))  // Solid color

// Key properties
sprite.anchorPoint = CGPoint(x: 0.5, y: 0)   // Bottom-center
sprite.colorBlendFactor = 0.5                  // Tint strength (0-1)
sprite.color = .red                            // Tint color
sprite.normalTexture = normalMap               // For lighting
sprite.lightingBitMask = 0x1                   // Which lights affect this
sprite.shadowCastBitMask = 0x1                 // Which lights cast shadows
sprite.shader = customShader                   // Per-pixel effects
swift
// 创建
SKSpriteNode(imageNamed: "player")           // 从资源目录
SKSpriteNode(texture: texture)                // 从SKTexture
SKSpriteNode(texture: texture, size: size)    // 自定义尺寸
SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))  // 纯色

// 关键属性
sprite.anchorPoint = CGPoint(x: 0.5, y: 0)   // 底部中心
sprite.colorBlendFactor = 0.5                  // 着色强度(0-1)
sprite.color = .red                            // 着色颜色
sprite.normalTexture = normalMap               // 用于光照
sprite.lightingBitMask = 0x1                   // 受哪些灯光影响
sprite.shadowCastBitMask = 0x1                 // 对哪些灯光投射阴影
sprite.shader = customShader                   // 逐像素效果

SKLabelNode Properties

SKLabelNode属性

swift
let label = SKLabelNode(text: "Score: 0")
label.fontName = "AvenirNext-Bold"
label.fontSize = 24
label.fontColor = .white
label.horizontalAlignmentMode = .left
label.verticalAlignmentMode = .top
label.numberOfLines = 0          // Multi-line (iOS 11+)
label.preferredMaxLayoutWidth = 200
label.lineBreakMode = .byWordWrapping

swift
let label = SKLabelNode(text: "Score: 0")
label.fontName = "AvenirNext-Bold"
label.fontSize = 24
label.fontColor = .white
label.horizontalAlignmentMode = .left
label.verticalAlignmentMode = .top
label.numberOfLines = 0          // 多行(iOS 11+)
label.preferredMaxLayoutWidth = 200
label.lineBreakMode = .byWordWrapping

Part 2: Physics API

第二部分:物理API

SKPhysicsBody Creation

SKPhysicsBody创建

swift
// Volume bodies (have mass, respond to forces)
SKPhysicsBody(circleOfRadius: 20)                    // Cheapest
SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 60))
SKPhysicsBody(polygonFrom: path)                     // Convex only
SKPhysicsBody(texture: texture, size: size)          // Pixel-perfect (expensive)
SKPhysicsBody(texture: texture, alphaThreshold: 0.5, size: size)
SKPhysicsBody(bodies: [body1, body2])                // Compound

// Edge bodies (massless boundaries)
SKPhysicsBody(edgeLoopFrom: rect)                    // Rectangle boundary
SKPhysicsBody(edgeLoopFrom: path)                    // Path boundary
SKPhysicsBody(edgeFrom: pointA, to: pointB)          // Single edge
SKPhysicsBody(edgeChainFrom: path)                   // Open path
swift
// 体积物理体(有质量,响应力)
SKPhysicsBody(circleOfRadius: 20)                    // 开销最低
SKPhysicsBody(rectangleOf: CGSize(width: 40, height: 60))
SKPhysicsBody(polygonFrom: path)                     // 仅支持凸多边形
SKPhysicsBody(texture: texture, size: size)          // 像素级精确(开销大)
SKPhysicsBody(texture: texture, alphaThreshold: 0.5, size: size)
SKPhysicsBody(bodies: [body1, body2])                // 复合物理体

// 边缘物理体(无质量边界)
SKPhysicsBody(edgeLoopFrom: rect)                    // 矩形边界
SKPhysicsBody(edgeLoopFrom: path)                    // 路径边界
SKPhysicsBody(edgeFrom: pointA, to: pointB)          // 单条边缘
SKPhysicsBody(edgeChainFrom: path)                   // 开放路径

Physics Body Properties

物理体属性

swift
// Identity
body.categoryBitMask = 0x1          // What this body IS
body.collisionBitMask = 0x2         // What it bounces off
body.contactTestBitMask = 0x4       // What triggers didBegin/didEnd

// Physical characteristics
body.mass = 1.0                     // kg
body.density = 1.0                  // kg/m^2 (auto-calculates mass)
body.friction = 0.2                 // 0.0 (ice) to 1.0 (rubber)
body.restitution = 0.3              // 0.0 (no bounce) to 1.0 (perfect bounce)
body.linearDamping = 0.1            // Air resistance (0 = none)
body.angularDamping = 0.1           // Rotational damping

// Behavior
body.isDynamic = true               // Responds to forces
body.affectedByGravity = true       // Subject to world gravity
body.allowsRotation = true          // Can rotate from physics
body.pinned = false                 // Pinned to parent position
body.usesPreciseCollisionDetection = false  // For fast objects

// Motion (read/write)
body.velocity = CGVector(dx: 100, dy: 0)
body.angularVelocity = 0.0

// Force application
body.applyForce(CGVector(dx: 0, dy: 100))           // Continuous
body.applyImpulse(CGVector(dx: 0, dy: 50))          // Instant
body.applyTorque(0.5)                                 // Continuous rotation
body.applyAngularImpulse(1.0)                         // Instant rotation
body.applyForce(CGVector(dx: 10, dy: 0), at: point)  // Force at point
swift
// 标识
body.categoryBitMask = 0x1          // 该物理体的类别
body.collisionBitMask = 0x2         // 会与之碰撞的类别
body.contactTestBitMask = 0x4       // 会触发didBegin/didEnd的类别

// 物理特性
body.mass = 1.0                     // 千克
body.density = 1.0                  // 千克/平方米(自动计算质量)
body.friction = 0.2                 // 0.0(冰)到1.0(橡胶)
body.restitution = 0.3              // 0.0(无反弹)到1.0(完美反弹)
body.linearDamping = 0.1            // 空气阻力(0=无)
body.angularDamping = 0.1           // 旋转阻尼

// 行为
body.isDynamic = true               // 响应力
body.affectedByGravity = true       // 受世界重力影响
body.allowsRotation = true          // 可因物理效果旋转
body.pinned = false                 // 是否固定在父节点位置
body.usesPreciseCollisionDetection = false  // 用于快速移动的物体

// 运动(可读可写)
body.velocity = CGVector(dx: 100, dy: 0)
body.angularVelocity = 0.0

// 施加力
body.applyForce(CGVector(dx: 0, dy: 100))           // 持续力
body.applyImpulse(CGVector(dx: 0, dy: 50))          // 瞬时冲量
body.applyTorque(0.5)                                 // 持续旋转力
body.applyAngularImpulse(1.0)                         // 瞬时旋转冲量
body.applyForce(CGVector(dx: 10, dy: 0), at: point)  // 在指定点施加力

SKPhysicsWorld

SKPhysicsWorld

swift
scene.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
scene.physicsWorld.speed = 1.0        // 0 = paused, 2 = double speed
scene.physicsWorld.contactDelegate = self

// Ray casting
let body = scene.physicsWorld.body(at: point)
let bodyInRect = scene.physicsWorld.body(in: rect)
scene.physicsWorld.enumerateBodies(alongRayStart: start, end: end) { body, point, normal, stop in
    // Process each body the ray intersects
}
swift
scene.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
scene.physicsWorld.speed = 1.0        // 0=暂停,2=两倍速度
scene.physicsWorld.contactDelegate = self

// 射线检测
let body = scene.physicsWorld.body(at: point)
let bodyInRect = scene.physicsWorld.body(in: rect)
scene.physicsWorld.enumerateBodies(alongRayStart: start, end: end) { body, point, normal, stop in
    // 处理射线相交的每个物理体
}

Physics Joints

物理关节

swift
// Pin joint (pivot)
let pin = SKPhysicsJointPin.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: anchorPoint
)

// Fixed joint (rigid connection)
let fixed = SKPhysicsJointFixed.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: anchorPoint
)

// Spring joint
let spring = SKPhysicsJointSpring.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchorA: pointA, anchorB: pointB
)
spring.frequency = 1.0    // Oscillations per second
spring.damping = 0.5       // 0 = no damping

// Sliding joint (linear constraint)
let slide = SKPhysicsJointSliding.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: point, axis: CGVector(dx: 1, dy: 0)
)

// Limit joint (distance constraint)
let limit = SKPhysicsJointLimit.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchorA: pointA, anchorB: pointB
)

// Add joint to world
scene.physicsWorld.add(joint)
// Remove: scene.physicsWorld.remove(joint)
swift
// 销钉关节(枢轴)
let pin = SKPhysicsJointPin.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: anchorPoint
)

// 固定关节(刚性连接)
let fixed = SKPhysicsJointFixed.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: anchorPoint
)

// 弹簧关节
let spring = SKPhysicsJointSpring.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchorA: pointA, anchorB: pointB
)
spring.frequency = 1.0    // 每秒振荡次数
spring.damping = 0.5       // 0=无阻尼

// 滑动关节(线性约束)
let slide = SKPhysicsJointSliding.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchor: point, axis: CGVector(dx: 1, dy: 0)
)

// 限制关节(距离约束)
let limit = SKPhysicsJointLimit.joint(
    withBodyA: bodyA, bodyB: bodyB,
    anchorA: pointA, anchorB: pointB
)

// 将关节添加到物理世界
scene.physicsWorld.add(joint)
// 移除:scene.physicsWorld.remove(joint)

Physics Fields

物理场

swift
// Gravity (directional)
let gravity = SKFieldNode.linearGravityField(withVector: vector_float3(0, -9.8, 0))

// Radial gravity (toward/away from point)
let radial = SKFieldNode.radialGravityField()
radial.strength = 5.0

// Electric field (charge-dependent)
let electric = SKFieldNode.electricField()

// Noise field (turbulence)
let noise = SKFieldNode.noiseField(withSmoothness: 0.5, animationSpeed: 1.0)

// Vortex
let vortex = SKFieldNode.vortexField()

// Drag
let drag = SKFieldNode.dragField()

// All fields share:
field.region = SKRegion(radius: 100)     // Area of effect
field.strength = 1.0                      // Intensity
field.falloff = 0.0                       // Distance falloff
field.minimumRadius = 10                  // Inner dead zone
field.isEnabled = true
field.categoryBitMask = 0xFFFFFFFF        // Which bodies affected

swift
// 重力(方向型)
let gravity = SKFieldNode.linearGravityField(withVector: vector_float3(0, -9.8, 0))

// 径向重力(朝向/远离某点)
let radial = SKFieldNode.radialGravityField()
radial.strength = 5.0

// 电场(依赖电荷)
let electric = SKFieldNode.electricField()

// 噪声场(湍流)
let noise = SKFieldNode.noiseField(withSmoothness: 0.5, animationSpeed: 1.0)

// 漩涡
let vortex = SKFieldNode.vortexField()

// 阻力
let drag = SKFieldNode.dragField()

// 所有场共享以下属性:
field.region = SKRegion(radius: 100)     // 作用区域
field.strength = 1.0                      // 强度
field.falloff = 0.0                       // 距离衰减
field.minimumRadius = 10                  // 内部盲区
field.isEnabled = true
field.categoryBitMask = 0xFFFFFFFF        // 影响哪些物理体

Part 3: Action Catalog

第三部分:动作目录

Movement

移动

swift
SKAction.move(to: point, duration: 1.0)
SKAction.move(by: CGVector(dx: 100, dy: 0), duration: 0.5)
SKAction.moveTo(x: 200, duration: 1.0)
SKAction.moveTo(y: 300, duration: 1.0)
SKAction.moveBy(x: 50, y: 0, duration: 0.5)
SKAction.follow(path, asOffset: true, orientToPath: true, duration: 2.0)
swift
SKAction.move(to: point, duration: 1.0)
SKAction.move(by: CGVector(dx: 100, dy: 0), duration: 0.5)
SKAction.moveTo(x: 200, duration: 1.0)
SKAction.moveTo(y: 300, duration: 1.0)
SKAction.moveBy(x: 50, y: 0, duration: 0.5)
SKAction.follow(path, asOffset: true, orientToPath: true, duration: 2.0)

Rotation

旋转

swift
SKAction.rotate(byAngle: .pi, duration: 1.0)        // Relative
SKAction.rotate(toAngle: .pi / 2, duration: 0.5)    // Absolute
SKAction.rotate(toAngle: angle, duration: 0.5, shortestUnitArc: true)
swift
SKAction.rotate(byAngle: .pi, duration: 1.0)        // 相对旋转
SKAction.rotate(toAngle: .pi / 2, duration: 0.5)    // 绝对旋转
SKAction.rotate(toAngle: angle, duration: 0.5, shortestUnitArc: true)

Scaling

缩放

swift
SKAction.scale(to: 2.0, duration: 0.5)
SKAction.scale(by: 1.5, duration: 0.3)
SKAction.scaleX(to: 2.0, y: 1.0, duration: 0.5)
SKAction.resize(toWidth: 100, height: 50, duration: 0.5)
swift
SKAction.scale(to: 2.0, duration: 0.5)
SKAction.scale(by: 1.5, duration: 0.3)
SKAction.scaleX(to: 2.0, y: 1.0, duration: 0.5)
SKAction.resize(toWidth: 100, height: 50, duration: 0.5)

Fading

淡入淡出

swift
SKAction.fadeIn(withDuration: 0.5)
SKAction.fadeOut(withDuration: 0.5)
SKAction.fadeAlpha(to: 0.5, duration: 0.3)
SKAction.fadeAlpha(by: -0.2, duration: 0.3)
swift
SKAction.fadeIn(withDuration: 0.5)
SKAction.fadeOut(withDuration: 0.5)
SKAction.fadeAlpha(to: 0.5, duration: 0.3)
SKAction.fadeAlpha(by: -0.2, duration: 0.3)

Composition

组合动作

swift
SKAction.sequence([action1, action2, action3])       // Sequential
SKAction.group([action1, action2])                    // Parallel
SKAction.repeat(action, count: 5)                     // Finite repeat
SKAction.repeatForever(action)                         // Infinite
action.reversed()                                      // Reverse
SKAction.wait(forDuration: 1.0)                       // Delay
SKAction.wait(forDuration: 1.0, withRange: 0.5)      // Random delay
swift
SKAction.sequence([action1, action2, action3])       // 顺序执行
SKAction.group([action1, action2])                    // 并行执行
SKAction.repeat(action, count: 5)                     // 有限次重复
SKAction.repeatForever(action)                         // 无限重复
action.reversed()                                      // 反向执行
SKAction.wait(forDuration: 1.0)                       // 延迟
SKAction.wait(forDuration: 1.0, withRange: 0.5)      // 随机延迟

Texture & Color

纹理与颜色

swift
SKAction.setTexture(texture)
SKAction.setTexture(texture, resize: true)
SKAction.animate(with: [tex1, tex2, tex3], timePerFrame: 0.1)
SKAction.animate(with: textures, timePerFrame: 0.1, resize: false, restore: true)
SKAction.colorize(with: .red, colorBlendFactor: 1.0, duration: 0.5)
SKAction.colorize(withColorBlendFactor: 0, duration: 0.5)
swift
SKAction.setTexture(texture)
SKAction.setTexture(texture, resize: true)
SKAction.animate(with: [tex1, tex2, tex3], timePerFrame: 0.1)
SKAction.animate(with: textures, timePerFrame: 0.1, resize: false, restore: true)
SKAction.colorize(with: .red, colorBlendFactor: 1.0, duration: 0.5)
SKAction.colorize(withColorBlendFactor: 0, duration: 0.5)

Sound

声音

swift
SKAction.playSoundFileNamed("explosion.wav", waitForCompletion: false)
swift
SKAction.playSoundFileNamed("explosion.wav", waitForCompletion: false)

Node Tree

节点树

swift
SKAction.removeFromParent()
SKAction.run(block)
SKAction.run(block, queue: .main)
SKAction.customAction(withDuration: 1.0) { node, elapsed in
    // Custom per-frame logic
}
swift
SKAction.removeFromParent()
SKAction.run(block)
SKAction.run(block, queue: .main)
SKAction.customAction(withDuration: 1.0) { node, elapsed in
    // 自定义每帧逻辑
}

Physics

物理相关动作

swift
SKAction.applyForce(CGVector(dx: 0, dy: 100), duration: 0.5)
SKAction.applyImpulse(CGVector(dx: 50, dy: 0), duration: 1.0/60.0)  // ~1 frame
SKAction.applyTorque(0.5, duration: 1.0)
SKAction.changeCharge(to: 1.0, duration: 0.5)
SKAction.changeMass(to: 2.0, duration: 0.5)
swift
SKAction.applyForce(CGVector(dx: 0, dy: 100), duration: 0.5)
SKAction.applyImpulse(CGVector(dx: 50, dy: 0), duration: 1.0/60.0)  // ~1帧
SKAction.applyTorque(0.5, duration: 1.0)
SKAction.changeCharge(to: 1.0, duration: 0.5)
SKAction.changeMass(to: 2.0, duration: 0.5)

Timing Modes

时间模式

swift
action.timingMode = .linear          // Constant speed
action.timingMode = .easeIn          // Slow → fast
action.timingMode = .easeOut         // Fast → slow
action.timingMode = .easeInEaseOut   // Slow → fast → slow

action.speed = 2.0                   // 2x speed

swift
action.timingMode = .linear          // 匀速
action.timingMode = .easeIn          // 慢→快
action.timingMode = .easeOut         // 快→慢
action.timingMode = .easeInEaseOut   // 慢→快→慢

action.speed = 2.0                   // 2倍速度

Part 4: Textures and Atlases

第四部分:纹理与图集

SKTexture

SKTexture

swift
// From image
let tex = SKTexture(imageNamed: "player")

// From atlas
let atlas = SKTextureAtlas(named: "Characters")
let tex = atlas.textureNamed("player_run_1")

// Subrectangle (for manual sprite sheets)
let sub = SKTexture(rect: CGRect(x: 0, y: 0, width: 0.25, height: 0.5), in: sheetTexture)

// From CGImage
let tex = SKTexture(cgImage: cgImage)

// Filtering
tex.filteringMode = .nearest    // Pixel art (no smoothing)
tex.filteringMode = .linear     // Smooth scaling (default)

// Preload
SKTexture.preload([tex1, tex2]) { /* Ready */ }
swift
// 从图片
let tex = SKTexture(imageNamed: "player")

// 从图集
let atlas = SKTextureAtlas(named: "Characters")
let tex = atlas.textureNamed("player_run_1")

// 子矩形(用于手动精灵表)
let sub = SKTexture(rect: CGRect(x: 0, y: 0, width: 0.25, height: 0.5), in: sheetTexture)

// 从CGImage
let tex = SKTexture(cgImage: cgImage)

// 过滤
tex.filteringMode = .nearest    // 像素风格(无平滑)
tex.filteringMode = .linear     // 平滑缩放(默认)

// 预加载
SKTexture.preload([tex1, tex2]) { /* 准备就绪 */ }

SKTextureAtlas

SKTextureAtlas

swift
// Create in Xcode: Assets.xcassets → New Sprite Atlas
// Or .atlas folder in project bundle

let atlas = SKTextureAtlas(named: "Characters")
let textureNames = atlas.textureNames  // All texture names in atlas

// Preload entire atlas
atlas.preload { /* Atlas ready */ }

// Preload multiple atlases
SKTextureAtlas.preloadTextureAtlases([atlas1, atlas2]) { /* All ready */ }

// Animation from atlas
let frames = (1...8).map { atlas.textureNamed("run_\($0)") }
let animate = SKAction.animate(with: frames, timePerFrame: 0.1)

swift
// 在Xcode中创建:Assets.xcassets → 新建Sprite图集
// 或项目包中的.atlas文件夹

let atlas = SKTextureAtlas(named: "Characters")
let textureNames = atlas.textureNames  // 图集中的所有纹理名称

// 预加载整个图集
atlas.preload { /* 图集准备就绪 */ }

// 预加载多个图集
SKTextureAtlas.preloadTextureAtlases([atlas1, atlas2]) { /* 全部就绪 */ }

// 从图集创建动画
let frames = (1...8).map { atlas.textureNamed("run_\($0)") }
let animate = SKAction.animate(with: frames, timePerFrame: 0.1)

Part 5: Constraints

第五部分:约束

swift
// Orient toward another node
let orient = SKConstraint.orient(to: targetNode, offset: SKRange(constantValue: 0))

// Orient toward a point
let orient = SKConstraint.orient(to: point, offset: SKRange(constantValue: 0))

// Position constraint (keep X in range)
let xRange = SKConstraint.positionX(SKRange(lowerLimit: 0, upperLimit: 400))

// Position constraint (keep Y in range)
let yRange = SKConstraint.positionY(SKRange(lowerLimit: 50, upperLimit: 750))

// Distance constraint (stay within range of node)
let dist = SKConstraint.distance(SKRange(lowerLimit: 50, upperLimit: 200), to: targetNode)

// Rotation constraint
let rot = SKConstraint.zRotation(SKRange(lowerLimit: -.pi/4, upperLimit: .pi/4))

// Apply constraints (processed in order)
node.constraints = [orient, xRange, yRange]

// Toggle
node.constraints?.first?.isEnabled = false
swift
// 朝向另一个节点
let orient = SKConstraint.orient(to: targetNode, offset: SKRange(constantValue: 0))

// 朝向某个点
let orient = SKConstraint.orient(to: point, offset: SKRange(constantValue: 0))

// 位置约束(保持X在范围内)
let xRange = SKConstraint.positionX(SKRange(lowerLimit: 0, upperLimit: 400))

// 位置约束(保持Y在范围内)
let yRange = SKConstraint.positionY(SKRange(lowerLimit: 50, upperLimit: 750))

// 距离约束(与节点保持在范围内)
let dist = SKConstraint.distance(SKRange(lowerLimit: 50, upperLimit: 200), to: targetNode)

// 旋转约束
let rot = SKConstraint.zRotation(SKRange(lowerLimit: -.pi/4, upperLimit: .pi/4))

// 应用约束(按顺序处理)
node.constraints = [orient, xRange, yRange]

// 启用/禁用
node.constraints?.first?.isEnabled = false

SKRange

SKRange

swift
SKRange(constantValue: 100)                    // Exactly 100
SKRange(lowerLimit: 50, upperLimit: 200)       // 50...200
SKRange(lowerLimit: 0)                          // >= 0
SKRange(upperLimit: 500)                        // <= 500
SKRange(value: 100, variance: 20)              // 80...120

swift
SKRange(constantValue: 100)                    // 精确值100
SKRange(lowerLimit: 50, upperLimit: 200)       // 50到200
SKRange(lowerLimit: 0)                          // 大于等于0
SKRange(upperLimit: 500)                        // 小于等于500
SKRange(value: 100, variance: 20)              // 80到120

Part 6: Scene Setup

第六部分:场景设置

SKView Configuration

SKView配置

swift
let skView = SKView(frame: view.bounds)

// Debug overlays
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.showsPhysics = true
skView.showsFields = true
skView.showsQuadCount = true

// Performance
skView.ignoresSiblingOrder = true        // Enables batching optimizations
skView.shouldCullNonVisibleNodes = true  // Auto-hide offscreen (manual is faster)
skView.isAsynchronous = true             // Default: renders asynchronously
skView.allowsTransparency = false        // Opaque is faster

// Frame rate
skView.preferredFramesPerSecond = 60     // Or 120 for ProMotion

// Present scene
skView.presentScene(scene)
skView.presentScene(scene, transition: .fade(withDuration: 0.5))
swift
let skView = SKView(frame: view.bounds)

// 调试叠加层
skView.showsFPS = true
skView.showsNodeCount = true
skView.showsDrawCount = true
skView.showsPhysics = true
skView.showsFields = true
skView.showsQuadCount = true

// 性能
skView.ignoresSiblingOrder = true        // 启用批处理优化
skView.shouldCullNonVisibleNodes = true  // 自动隐藏屏幕外节点(手动处理更快)
skView.isAsynchronous = true             // 默认:异步渲染
skView.allowsTransparency = false        // 不透明模式更快

// 帧率
skView.preferredFramesPerSecond = 60     // 或120适配ProMotion

// 呈现场景
skView.presentScene(scene)
skView.presentScene(scene, transition: .fade(withDuration: 0.5))

Scale Mode Matrix

缩放模式矩阵

ModeAspect RatioContentBest For
.aspectFill
PreservedFills view, crops edgesMost games
.aspectFit
PreservedFits in view, letterboxesExact layout needed
.resizeFill
DistortedStretches to fillAlmost never
.fill
VariesScene resizes to match viewAdaptive scenes
模式宽高比内容表现最佳适用场景
.aspectFill
保持填充视图,裁剪边缘大多数游戏
.aspectFit
保持适配视图,留黑边需要精确布局的场景
.resizeFill
扭曲拉伸填充几乎不使用
.fill
变化场景调整大小以匹配视图自适应场景

SKTransition Types

SK转场类型

swift
SKTransition.fade(withDuration: 0.5)
SKTransition.fade(with: .black, duration: 0.5)
SKTransition.crossFade(withDuration: 0.5)
SKTransition.flipHorizontal(withDuration: 0.5)
SKTransition.flipVertical(withDuration: 0.5)
SKTransition.reveal(with: .left, duration: 0.5)
SKTransition.moveIn(with: .right, duration: 0.5)
SKTransition.push(with: .up, duration: 0.5)
SKTransition.doorway(withDuration: 0.5)
SKTransition.doorsOpenHorizontal(withDuration: 0.5)
SKTransition.doorsOpenVertical(withDuration: 0.5)
SKTransition.doorsCloseHorizontal(withDuration: 0.5)
SKTransition.doorsCloseVertical(withDuration: 0.5)
// Custom with CIFilter:
SKTransition(ciFilter: filter, duration: 0.5)

swift
SKTransition.fade(withDuration: 0.5)
SKTransition.fade(with: .black, duration: 0.5)
SKTransition.crossFade(withDuration: 0.5)
SKTransition.flipHorizontal(withDuration: 0.5)
SKTransition.flipVertical(withDuration: 0.5)
SKTransition.reveal(with: .left, duration: 0.5)
SKTransition.moveIn(with: .right, duration: 0.5)
SKTransition.push(with: .up, duration: 0.5)
SKTransition.doorway(withDuration: 0.5)
SKTransition.doorsOpenHorizontal(withDuration: 0.5)
SKTransition.doorsOpenVertical(withDuration: 0.5)
SKTransition.doorsCloseHorizontal(withDuration: 0.5)
SKTransition.doorsCloseVertical(withDuration: 0.5)
// 使用CIFilter自定义:
SKTransition(ciFilter: filter, duration: 0.5)

Part 7: Particles

第七部分:粒子系统

SKEmitterNode Key Properties

SKEmitterNode关键属性

swift
let emitter = SKEmitterNode(fileNamed: "Spark")!

// Emission control
emitter.particleBirthRate = 100          // Particles per second
emitter.numParticlesToEmit = 0           // 0 = infinite
emitter.particleLifetime = 2.0           // Seconds
emitter.particleLifetimeRange = 0.5      // ± random

// Position
emitter.particlePosition = .zero
emitter.particlePositionRange = CGVector(dx: 10, dy: 10)

// Movement
emitter.emissionAngle = .pi / 2         // Direction (radians)
emitter.emissionAngleRange = .pi / 4    // Spread
emitter.particleSpeed = 100              // Points per second
emitter.particleSpeedRange = 50          // ± random
emitter.xAcceleration = 0
emitter.yAcceleration = -100             // Gravity-like

// Appearance
emitter.particleTexture = SKTexture(imageNamed: "spark")
emitter.particleSize = CGSize(width: 8, height: 8)
emitter.particleColor = .white
emitter.particleColorAlphaSpeed = -0.5   // Fade out
emitter.particleBlendMode = .add         // Additive for fire/glow
emitter.particleAlpha = 1.0
emitter.particleAlphaSpeed = -0.5

// Scale
emitter.particleScale = 1.0
emitter.particleScaleRange = 0.5
emitter.particleScaleSpeed = -0.3        // Shrink over time

// Rotation
emitter.particleRotation = 0
emitter.particleRotationSpeed = 2.0

// Target node (for trails)
emitter.targetNode = scene               // Particles stay in world space

// Render order
emitter.particleRenderOrder = .dontCare  // .oldestFirst, .oldestLast, .dontCare

// Physics field interaction
emitter.fieldBitMask = 0x1
swift
let emitter = SKEmitterNode(fileNamed: "Spark")!

// 发射控制
emitter.particleBirthRate = 100          // 每秒发射粒子数
emitter.numParticlesToEmit = 0           // 0=无限发射
emitter.particleLifetime = 2.0           // 粒子生命周期(秒)
emitter.particleLifetimeRange = 0.5      // 随机波动范围±

// 位置
emitter.particlePosition = .zero
emitter.particlePositionRange = CGVector(dx: 10, dy: 10)

// 运动
emitter.emissionAngle = .pi / 2         // 发射方向(弧度)
emitter.emissionAngleRange = .pi / 4    // 发射扩散角度
emitter.particleSpeed = 100              // 粒子速度(点/秒)
emitter.particleSpeedRange = 50          // 速度随机波动范围±
emitter.xAcceleration = 0
emitter.yAcceleration = -100             // 类重力加速度

// 外观
emitter.particleTexture = SKTexture(imageNamed: "spark")
emitter.particleSize = CGSize(width: 8, height: 8)
emitter.particleColor = .white
emitter.particleColorAlphaSpeed = -0.5   // 淡出速度
emitter.particleBlendMode = .add         // 叠加混合(用于火焰/发光效果)
emitter.particleAlpha = 1.0
emitter.particleAlphaSpeed = -0.5

// 缩放
emitter.particleScale = 1.0
emitter.particleScaleRange = 0.5
emitter.particleScaleSpeed = -0.3        // 随时间缩小

// 旋转
emitter.particleRotation = 0
emitter.particleRotationSpeed = 2.0

// 目标节点(用于轨迹)
emitter.targetNode = scene               // 粒子保留在世界空间

// 渲染顺序
emitter.particleRenderOrder = .dontCare  // .oldestFirst, .oldestLast, .dontCare

// 物理场交互
emitter.fieldBitMask = 0x1

Common Particle Presets

常见粒子预设

EffectKey Settings
Fire
blendMode: .add
, fast
alphaSpeed
, orange→red color, upward speed
Smoke
blendMode: .alpha
, slow speed, gray color, scale up over time
Sparks
blendMode: .add
, high speed + range, short lifetime, small size
RainDownward
emissionAngle
, narrow range, long lifetime, thin texture
SnowSlow downward speed, wide position range, slight x acceleration
TrailSet
targetNode
to scene, narrow emission angle, medium lifetime
ExplosionHigh birth rate, short
numParticlesToEmit
, high speed range

效果关键设置
火焰
blendMode: .add
,快速
alphaSpeed
,橙→红颜色,向上速度
烟雾
blendMode: .alpha
,低速,灰色,随时间放大
火花
blendMode: .add
,高速+大范围,短生命周期,小尺寸
向下
emissionAngle
,窄扩散范围,长生命周期,细长纹理
低速下落,宽位置范围,轻微x方向加速度
轨迹设置
targetNode
为场景,窄发射角度,中等生命周期
爆炸高发射速率,
numParticlesToEmit
值小,高速范围

Part 8: SKRenderer and Shaders

第八部分:SKRenderer与着色器

SKRenderer (Metal Integration)

SKRenderer(Metal集成)

swift
import MetalKit

let device = MTLCreateSystemDefaultDevice()!
let renderer = SKRenderer(device: device)
renderer.scene = gameScene
renderer.ignoresSiblingOrder = true

// In Metal render loop:
func draw(in view: MTKView) {
    guard let commandBuffer = commandQueue.makeCommandBuffer(),
          let rpd = view.currentRenderPassDescriptor else { return }

    renderer.update(atTime: CACurrentMediaTime())
    renderer.render(
        withViewport: CGRect(origin: .zero, size: view.drawableSize),
        commandBuffer: commandBuffer,
        renderPassDescriptor: rpd
    )

    commandBuffer.present(view.currentDrawable!)
    commandBuffer.commit()
}
swift
import MetalKit

let device = MTLCreateSystemDefaultDevice()!
let renderer = SKRenderer(device: device)
renderer.scene = gameScene
renderer.ignoresSiblingOrder = true

// 在Metal渲染循环中:
func draw(in view: MTKView) {
    guard let commandBuffer = commandQueue.makeCommandBuffer(),
          let rpd = view.currentRenderPassDescriptor else { return }

    renderer.update(atTime: CACurrentMediaTime())
    renderer.render(
        withViewport: CGRect(origin: .zero, size: view.drawableSize),
        commandBuffer: commandBuffer,
        renderPassDescriptor: rpd
    )

    commandBuffer.present(view.currentDrawable!)
    commandBuffer.commit()
}

SKShader (Custom GLSL ES Effects)

SKShader(自定义GLSL ES效果)

swift
// Fragment shader for per-pixel effects
let shader = SKShader(source: """
    void main() {
        vec4 color = texture2D(u_texture, v_tex_coord);
        // Desaturate
        float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        gl_FragColor = vec4(vec3(gray), color.a) * v_color_mix.a;
    }
""")

sprite.shader = shader

// With uniforms
let shader = SKShader(source: """
    void main() {
        vec4 color = texture2D(u_texture, v_tex_coord);
        color.rgb *= u_intensity;
        gl_FragColor = color;
    }
""")
shader.uniforms = [
    SKUniform(name: "u_intensity", float: 0.8)
]

// Built-in uniforms:
// u_texture     — sprite texture
// u_time        — elapsed time
// u_path_length — shape node path length
// v_tex_coord   — texture coordinate
// v_color_mix   — color/alpha mix
// SKAttribute for per-node values
swift
// 用于逐像素效果的片段着色器
let shader = SKShader(source: """
    void main() {
        vec4 color = texture2D(u_texture, v_tex_coord);
        // 去饱和
        float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
        gl_FragColor = vec4(vec3(gray), color.a) * v_color_mix.a;
    }
""")

sprite.shader = shader

// 带Uniforms
let shader = SKShader(source: """
    void main() {
        vec4 color = texture2D(u_texture, v_tex_coord);
        color.rgb *= u_intensity;
        gl_FragColor = color;
    }
""")
shader.uniforms = [
    SKUniform(name: "u_intensity", float: 0.8)
]

// 内置Uniforms:
// u_texture     — 精灵纹理
// u_time        — 已流逝时间
// u_path_length — 形状节点路径长度
// v_tex_coord   — 纹理坐标
// v_color_mix   — 颜色/alpha混合
// SKAttribute用于每个节点的自定义值

Resources

资源

WWDC: 2014-608, 2016-610, 2017-609
Docs: /spritekit/skspritenode, /spritekit/skphysicsbody, /spritekit/skaction, /spritekit/skemitternode, /spritekit/skrenderer
Skills: axiom-spritekit, axiom-spritekit-diag
WWDC: 2014-608, 2016-610, 2017-609
文档: /spritekit/skspritenode, /spritekit/skphysicsbody, /spritekit/skaction, /spritekit/skemitternode, /spritekit/skrenderer
技能: axiom-spritekit, axiom-spritekit-diag