Розробка мобільної гри на SceneKit (iOS)
SceneKit — нативний 3D-фреймворк Apple поверх Metal. З'явився в iOS 8, суттєво виріс у iOS 12–16. Це не Unity та не Unreal: немає візуального редактора пайплайну, немає Asset Store, менше готових рішень. Але це також не сирий Metal: фізичний движок, анімації, shader модифікатори, AR-інтеграція через ARKit — все входить в SDK без сторонніх залежностей. Для iOS-екзклюзивних 3D-ігор середної складності — цілком працюючий варіант, особливо якщо команда глибоко в Swift/Objective-C.
Сцена, ноди, рендеринг
Базова одиниця — SCNNode. Сцена — дерево нодів: корінь SCNScene.rootNode, до нодів прикріплені геометрія (SCNGeometry), світло (SCNLight), камера (SCNCamera), фізичне тіло (SCNPhysicsBody). Відмінність від SpriteKit у тому, що SceneKit працює в 3D-просторі з координатами SCNVector3, а трансформації задаються через simd_float4x4 (або зручні властивості position, eulerAngles, simdTransform).
Завантажимо сцену з .scn-файлу (редагується прямо в Xcode Scene Editor):
guard let scene = SCNScene(named: "GameLevel.scn") else {
fatalError("Scene not found")
}
let scnView = SCNView(frame: view.bounds)
scnView.scene = scene
scnView.allowsCameraControl = false
scnView.rendersContinuously = true // важливо для анімацій
view.addSubview(scnView)
rendersContinuously = true — якщо не встановити, SCNView рендерит лише при зміні сцени. Для ігор з постійним рухом потрібен постійний рендер. Зворотна сторона — витрата батареї. Для меню з рідкими змінами залишаємо false.
Фізика та коллізії в 3D
SCNPhysicsBody трьох типів: .static (нерухомі об'єкти, коллайдер не рухається), .dynamic (під управлінням фізики), .kinematic (рухається кодом, ігнорує сили, але участвує в коллізіях). Персонаж гравця зазвичай kinematic — ми рухаємо його через код, але стіни та підлога його зупиняють.
Форма коллайдера впливає на продуктивність сильніше, ніж у 2D:
// Дорого: SCNPhysicsShape(geometry: complexMesh) — convex hull для 10k вершин
// Нормально: bounding box або capsule для персонажа
let capsule = SCNCapsule(capRadius: 0.3, height: 1.8)
let physicsShape = SCNPhysicsShape(geometry: capsule, options: nil)
player.physicsBody = SCNPhysicsBody(type: .kinematic, shape: physicsShape)
Коллізії через SCNPhysicsContactDelegate:
func physicsWorld(_ world: SCNPhysicsWorld,
didBegin contact: SCNPhysicsContact) {
let nodeA = contact.nodeA
let nodeB = contact.nodeB
// Обробляємо столкновение
}
categoryBitMask, collisionBitMask, contactTestBitMask — та сама бітмаск-система, що й у SpriteKit. Правило: встановлювати contactTestBitMask лише для пар, які реально потрібно обробляти, інакше didBegin буде вызиватися занадто часто.
Анімації: CAAnimation та SCNAnimationPlayer
SceneKit підтримує анімації з .dae (Collada) та .usdz файлів. Для скелетної анімації персонажа — імпорт з .dae:
let idleScene = SCNScene(named: "character_idle.dae")!
// Витягуємо анімацію з сцени
if let animationKey = idleScene.rootNode.animationKeys.first,
let animation = idleScene.rootNode.animationPlayer(forKey: animationKey) {
characterNode.addAnimationPlayer(animation, forKey: "idle")
animation.play()
}
Переключення між анімаціями (idle → run → jump) реалізуємо через SCNAnimationPlayer з blendInDuration для плавного переходу:
func transition(to key: String, blendDuration: CGFloat = 0.3) {
guard let player = characterNode.animationPlayer(forKey: key) else { return }
player.blendInDuration = blendDuration
player.play()
// Зупиняємо поточну
currentAnimationKey.flatMap { characterNode.animationPlayer(forKey: $0) }?.stop(blendOutDuration: blendDuration)
currentAnimationKey = key
}
Без blendInDuration персонаж «стрибає» між позами — це перше, що помічає гравець.
Шейдери та постефекти
SceneKit дозволяє підключати GLSL/Metal шейдери через SCNMaterial.shaderModifiers. Чотири точки підключення: .geometry, .surface, .lightingModel, .fragment. Типовое застосування — розчинення об'єкта при смерті:
let dissolveShader = """
#pragma transparent
#pragma body
float threshold = u_dissolveAmount;
float noise = ... // шум за координатами
if (noise < threshold) discard_fragment();
_output.color.a = smoothstep(threshold - 0.05, threshold, noise);
"""
material.shaderModifiers = [.fragment: dissolveShader]
SCNTechnique — для постобробки всього екрана (bloom, outline, depth of field). Конфігурується через plist-словник з описанням passes та render targets. Складніше, ніж у Unity, але працює поверх Metal без додаткових бібліотек.
ARKit інтеграція
SceneKit — перший та основний рендерер для ARKit:
let arView = ARSCNView(frame: view.bounds)
let config = ARWorldTrackingConfiguration()
config.planeDetection = [.horizontal, .vertical]
arView.session.run(config)
ARSCNView автоматично синхронізує SCNScene з AR-координатним простором. ARSCNViewDelegate дозволяє реагувати на виявлення площин, додавати якорі. Це основа для AR-ігор — ринок ARKit + SceneKit добре закритий прикладами Apple.
Продуктивність: металл під капотом
SCNView за замовчуванням використовує Metal на iOS 9+. Декілька правил, які реально впливають на fps:
Batching: SceneKit автоматично об'єднує draw calls для нодів з одинаковим матеріалом. Тому «1000 дерев з одним матеріалом» набагато дешевше, ніж «100 дерев з 100 різними матеріалами». Використовуй SCNMaterial інстанси, не創й новий об'єкт матеріалу для кожного ноду.
Level of Detail через SCNLevelOfDetail:
let lods = [
SCNLevelOfDetail(geometry: mediumDetailMesh, worldSpaceDistance: 20),
SCNLevelOfDetail(geometry: lowDetailMesh, worldSpaceDistance: 50)
]
node.geometry?.levelsOfDetail = lods
Occlusion culling: SceneKit робить frustum culling автоматично, але occlusion culling (сховання об'єктів за іншими) — ні. Для складних сцен це потрібно робити вручну через isHidden = true за результатами ray cast або логіки рівня.
Інструмент для профайлінгу: Xcode → Metal System Trace + Render Graph (Instruments). Показує кількість draw calls, використання GPU, tile memory на Apple Silicon. Мета — не більше 30–50 draw calls для стабільних 60 fps на iPhone X.
Коли SceneKit не найкращий вибір
Мультиплатформа (iOS + Android + PC) — Unity або Godot. Складна фізика з деформацією тіл — Unity з Havok. Масивні відкриті світи — теж Unity/Unreal. SceneKit хорош для iOS-eksklusyvu з помірною 3D-складністю, AR-застосунків та ігор, де важлива нативна інтеграція (Game Center, CloudKit, Apple Silicon optimizations).
Етапи роботи
Аудит ТЗ: тип гри, потрібен AR, цільові пристрої, iOS-мінімум, ассеты (3D-моделі, анімації).
Прототип ігрової механіки: рух персонажа, фізика, базова камера — 1–2 тижні.
Core gameplay: рівні, враги / перешкоди, UI (SwiftUI поверх SCNView або UIKit-оверлей).
Аудіо: AVAudioEngine для 3D-звука через AVAudio3DMixing.
Game Center, IAP (якщо потрібно), ARKit (якщо AR-складова).
Полірування продуктивності, тестування на слабих пристроях.
Орієнтири по термінах
| Тип проекту | Термін |
|---|---|
| Прототип / proof of concept | 2–3 тижні |
| Казуальна 3D-гра без AR | 1,5–2 місяці |
| 3D-гра з AR + Game Center | 2–3 місяці |
| Складний проект (відкритий світ, мультиплеєр) | Обговорюється окремо |
Вартість розраховується індивідуально після аналізу ТЗ, наявності готових ассетів та вимог до платформ.







