Розробка мобільної гри на SpriteKit (iOS)

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Розробка мобільної гри на SpriteKit (iOS)
Середній
від 1 тижня до 3 місяців
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Розробка мобільної гри на SpriteKit (iOS)

SpriteKit — нативний 2D-фреймворк Apple, вбудований в iOS SDK з версії 7. Не потребує сторонніх залежностей, хорошо інтегрується з GameplayKit для логіки ІІ противників, показує стабільні 60 fps на iPhone SE другого покоління при розумному навантаженні. Для 2D-ігор з помірною складністю — розумний вибір, особливо якщо команда вже пише на Swift та не хоче тягти в проект Unity або Godot.

Архітектура гри: сцени, ноди та фізика

Все в SpriteKit — це дерево SKNode. SKScene — кореневий контейнер, SKSpriteNode — об'єкт, що відображається, SKEmitterNode — система частинок, SKLabelNode — текст. Типова помилка в перших проектах — створювати сцени як «моноліт», мішаючи логіку руху, відображення, звук та UI в одному файлі. При 200 рядках це вже нечитаємо.

Робочою структура через компонентний підхід з GKComponent з GameplayKit:

class EnemyNode: SKSpriteNode {
    var movementComponent: MovementComponent?
    var healthComponent: HealthComponent?
}

class MovementComponent: GKComponent {
    override func update(deltaTime seconds: TimeInterval) {
        guard let node = entity?.component(ofType: GKSKNodeComponent.self)?.node else { return }
        node.position.y -= CGFloat(150 * seconds)
    }
}

Це дозволяє тестувати MovementComponent ізольовано та переиспользувати між типами ворогів.

Фізичний движок SpriteKit заснований на Box2D. SKPhysicsBody трьох видів: circleOfRadius, rectangleOf(size:) та bodyWithTexture(_:alphaThreshold:size:) — останній генерує полігональний коллайдер по пікселям текстури. На практиці bodyWithTexture з alphaThreshold: 0.5 зручний, але дорогий: на складних текстурах генерація тіла займає ощутимий час. Кешуємо та переиспользуємо:

extension SKPhysicsBody {
    private static var cache: [String: SKPhysicsBody] = [:]

    static func cached(texture: SKTexture, size: CGSize, key: String) -> SKPhysicsBody {
        if let cached = cache[key] {
            return cached.copy() as! SKPhysicsBody
        }
        let body = SKPhysicsBody(texture: texture, alphaThreshold: 0.5, size: size)
        cache[key] = body
        return body.copy() as! SKPhysicsBody
    }
}

Коллізії встановлюються через categoryBitMask та contactTestBitMask. Типова проблема — пропуск коллізій при високій швидкості («туннелювання»). Рішення: usesPreciseCollisionDetection = true для швидких тіл, але це дорого по CPU. Альтернатива — SKPhysicsWorld.enumerateBodies(alongRayStart:end:using:) для ручних ray cast перевірок в update(_:).

Атлас текстур та продуктивність

Draw call — головний враг продуктивності в SpriteKit. Кожна унікальна текстура — потенційно окремий draw call. SKTextureAtlas групує спрайти в один атлас:

let atlas = SKTextureAtlas(named: "Enemies")
let texture = atlas.textureNamed("enemy_run_01")

Xcode компілює атлас автоматично з папки .spriteatlas. Правило: все, що рисується одночасно — в один атлас. Перевірити кількість draw calls можна в Xcode через View → Debug → Statistics прямо в симуляторі при запущеній грі.

При SKSpriteNode розміром 64×64 та текстурою 512×512 Metal виконує downscale на GPU кожен кадр. Текстури мають бути максимально близькі до розміру відображення. Xcode Instruments → Metal System Trace покаже, якщо GPU перевантажений ненужним масштабуванням.

Анімація через SKAction.animate(with:timePerFrame:):

let frames = (1...8).map { atlas.textureNamed("run_\(String(format: "%02d", $0))") }
let animation = SKAction.animate(with: frames, timePerFrame: 1.0/12.0, resize: false, restore: false)
let loop = SKAction.repeatForever(animation)
character.run(loop, withKey: "running")

withKey: дозволяє зупинити або замінити анімацію пізніше через removeAction(forKey:).

Звук: AVAudioEngine замість SKAction.playSoundFileNamed

SKAction.playSoundFileNamed(_:waitForCompletion:) — зручно для прототипу, але не годиться для продакшену: немає контролю громкості, немає можливості паузи, файл декодується при кожному вызові. Для ігор використовуємо AVAudioEngine з AVAudioPlayerNode:

class AudioManager {
    private let engine = AVAudioEngine()
    private var playerNodes: [String: AVAudioPlayerNode] = [:]
    private var audioFiles: [String: AVAudioFile] = [:]

    func preloadSound(named name: String) throws {
        let url = Bundle.main.url(forResource: name, withExtension: "wav")!
        audioFiles[name] = try AVAudioFile(forReading: url)
    }

    func playSound(named name: String) {
        guard let file = audioFiles[name] else { return }
        let node = AVAudioPlayerNode()
        engine.attach(node)
        engine.connect(node, to: engine.mainMixerNode, format: file.processingFormat)
        node.scheduleFile(file, at: nil)
        node.play()
    }
}

Передзавантажуємо звуки у фоні при старті сцени, не блокуючи main thread.

GameplayKit: поведінка ворогів без винаходу велосипеда

GKStateMachine чудово підходить для AI-станів ворога:

class EnemyIdleState: GKState {
    override func isValidNextState(_ stateClass: AnyClass) -> Bool {
        stateClass == EnemyChaseState.self || stateClass == EnemyAttackState.self
    }
}

GKAgent2D з GKGoal дозволяє реалізувати pursuit, flee, flocking без ручного програмування векторної математики. Для процедурної генерації рівнів — GKNoise та GKPerlinNoiseSource.

Типові проблеми в продакшені

Просадка FPS при появленні багатьох ворогів — частіше за все SKPhysicsBody у кожного з точними коллайдерами. Рішення: упростити коллайдери до circleOfRadius або rectangleOf, точну физику столкновення робити лише для гравця.

Утічки пам'яті при зміні сценSKScene не освобождается, якщо залишилися невідмінені SKAction з сильними посиланнями на об'єкти. Завжди вызивувати removeAllActions() в willMove(from:).

Текстури не виконуютьсяSKTextureAtlas тримається в пам'яті, поки хоча б один SKSpriteNode використовує його текстуру. При зміні рівня явно замінюємо текстури нодів на SKTexture() перед видаленням сцени, потім вызивувати removeFromParent().

Етапи роботи

Аудит ТЗ: жанр, кількість рівнів, монетизація (IAP, реклама), цільові пристрої, iOS-мінімум.

Прототип: core gameplay loop за першу тиждень — саме в цей момент зрозуміло, варто йти далі з SpriteKit або потрібен Unity.

Розробка: сцени, ігрова механіка, фізика, AI, звук, UI (окремана SKScene поверх ігрової або UIKit-оверлей через SKView).

Інтеграція Game Center: таблиці рекордів, досягнення.

Тестування на реальних пристроях: iPhone SE 2gen (слабий GPU), iPad Pro (великий екран, інший aspect ratio).

Публікація: App Store Connect, вікова оцінка, метадані.

Орієнтири по термінах

Складність гри Термін
Проста казуалка (1-3 механіки, 5-10 рівнів) 2–4 тижні
Середній проект (10+ рівнів, AI враги, IAP) 1,5–2 місяці
Повнофункціональна гра з контентом 2–3 місяці

Терміни сильно залежать від обсягу контенту (графіка, звук) — якщо ассеты готові, розробка швидша. Якщо потрібно створювати з нуля — додаємо час на дизайн.