Як це зроблено: мобільний багатоплатформовий движок

Для вас підготував серію статей про мобільному геймдеве, засновану на отриманому досвіді і пройдених граблях. У першій статті мова піде про створення власного міжплатформового рушія для мобільних ігор. По правді кажучи не лише мобільних, і не тільки ігор.


А чи потрібен свій движок взагалі?
Кожен раз, коли черговий популярний движок стає безкоштовним або відкритим, я задаю собі це питання. Давайте розглянемо плюси і мінуси:

Плюси

  • Ви завжди знаєте як працюють ваші проекти всередині, а головне можете впливати на їх роботу як побажаєте. Вам не потрібно штурмувати форуми розробників проханнями додати потрібний вам функціонал або пофіксити старі баги.
  • Ви зможете самостійно додавати підтримку нових платформ і додавати нові сторонні SDK.
  • Ви зможете використовувати будь-які зручні вам формати зберігання даних (графіка, звуки, ресурси).
  • Ви не обмежені ніякими ліцензіями.
Мінуси

  • Все доведеться писати самому, а так само вникати у всі нюанси кожної платформи. Цей процес займе досить багато часу, тому просто так «заради інтересу» цим займатися не варто. Інша справа, якщо ви займаєтеся геймдевом професійно і плануєте випускати досить багато ігор. Практика показує, що більшість ігрових студій рано чи пізно створюють свої SDK.
  • Якщо ви робите проекти на замовлення, то не всі замовники раді вашим самописным рішень. Адже можливо підтримувати проект доведеться зовсім іншим людям.
  • У багатьох популярних движках є вбудовані візуальні 2D/3D редактори. Про їх зручності можна довго сперечатися, але у вас не буде й цього.
Звичайно кожен для себе побачить свої плюси і мінуси. Моя справа попередити. Поїхали!

З чого це зроблено?
Ми говоримо в першу чергу про розробки мобільних ігор, тому основа буде однозначно C++/OpenGL. Без варіантів! Однак без другорядних мов теж не обійтися. Давайте подивимося що використовується на кожній платформі:
Платформа Основа Обгортка Графіка
iOS C++ ObjectiveC або Swift OpenGL
Android C++ (NDK) Java OpenGL
WindowsPhone C++ C# OpenGL через врапер або DirectX
tvOS (AppleTV) C++ ObjectiveC або Swift OpenGL
OSX C++ ObjectiveC або Swift OpenGL
Linux C++ C++ OpenGL
Як бачите C++ і OpenGL зустрічаються скрізь. На ObjectiveC/Java/C# доведеться написати лише обгортку для роботи з системою девайса. Сам же код ваших проектів буде єдиний — на З++. На цій ноті скажемо: «До побачення, болісне портування!».

OpenGL

Настійно рекомендую використовувати OpenGL 2.0 і вище. Час OpenGL 1.1 давно минуло, а перехід з 1.х на 2.х ви будете згадувати в кошмарних снах. Однак не поспішайте використовувати останню версію OpenGL не переконавшись, що всі цільові платформи його підтримують. У більшості випадків OpenGL 2.0 цілком вистачає і підтримують його всі платформи.

С++

Та ж ситуація і з С++11/14. Якщо впевнені, що всі компілятори з ним дружать – супер. Мені ж вистачає C++98, так що при додаванні нової платформи — а в планах є підтримка консолей — я буду спокійний.

IDE

Xcode – для iOS, OSX, tvOS. Плагіни через CocoaPods.
Android Studio – для Android. Плагіни через Gradle.
Visual Studio – все що під Windows.

Структура движка
Насамперед движок і проекти повинні акуратно і логічно зберігатися на диску. В підсумку я прийшов до такої структури:

  • Engine (все що стосується движка)
    • Classes (.h, .cpp файли движка)
    • Modules (модулі і сторонні SDK, які потрібні не у всіх проектах)
      • Рекламні SDK
      • Аналітика
      • Game Center
      • Зображення
      • Соціальні сітки
      • … і т. д.
    • Platforms (специфічні класи по платформах)
      • Android
      • iOS
      • OSX
      • tvOS
      • … інші платформи
  • Тестовий проект
    • iOS
      • Проект.xcworkspace
      • Icons (іконки програми, *auto — складальник проекту сам заповнює ці папки)
      • Launch (картинки при старті програми, *auto)
      • Res (готові ресурси програми, *auto)
      • Pods
      • … інші файли ios проекту, plist, будова і т. д.
    • Android, OSX, tvOS… такі ж за змістом папки під різні платформи і IDE. Для Android Studio своя структура проекту.
    • Assets
      • Icons (іконки додатка всіх розмірів)
      • Launch (ланч-скріни всіх розмірів)
    • Resources (оригінали ресурсів проекту)
      • General (основні ресурси для всіх платформ)
      • Lang (шрифти і локалізація)
        • Fonts (папка з SDF шрифтами)
        • Lang.xls файл з перекладами)

      • Platform (ресурси специфічні для платформи)
        • iOS
        • Android

        • … інші платформи
      • Shaders (шейдери)
      • Sounds (звуки)
        • MP3 (треки)
        • OGG (для звуків)

      • Textures (ресурси за форматами текстур)
        • ATI
        • ETC

        • PVRTC
        • S3TC
    • Source (.h, .cpp файли самого проекту)
    • Config (файл параметрів проекту для складальника)
Складальник проекту
Складальник проекту відповідає за підготовку ресурсів, формати і упаковку. А саме:
  • Бере іконки (чи навіть одну іконку максимального розміру 1024х1024) з Assets/Icons, робить інші розміри (від 16х16 до 1024х1024) і копіює в папки по платформах [Platform]/Icons
  • Так само надходить з екранами старту з Assets/Launch
  • Бере ресурси програми з таких папок:
    • Resources/General
    • Resources/Shaders

    • Resources/Sounds/MP3, OGG
    • Resources/Textures/[потрібний формат текстур]
    • Resources/Platform/[платформа]
    • Resources/Lang/Fonts
Далі складальник конвертує ресурси, шифрує, упаковує і поміщає в [Platform]/Res.

Найважливіше тут – це конвертація файлів по розширенню. Я використовую такі конвертації:
  • PNG та JPEG перетворюються в WEBP. Загальні настройки конвертації (наприклад мінімальна якість) можна винести в налаштування проекту Project/Config, а можна і прямо вказати в назві файлу.
    , Наприклад image~q100.png буде стиснута з параметром quality 100, а image~less.png буде стиснута без втрати якості.
    Так само добре себе зарекомендували пресети.
    Наприклад до image~p1.png буде застосований 1й пресет, який переверне зображення дзеркально і збереже з якістю 90%.
  • Текстові файли та шейдери (.txt, .vs, .ps) шифруються нехитрим способом. Простий захист від цікавих.
  • Файл локалізації Resources/Lang/Lang.xls парс з мов, шифрується і упаковується в бінарний формат.
  • На льоту створюються текстурні атласи. Наприклад папка folder~atlas будуть взяті всі картинки і упаковані в єдину картинку + збережеться файлик з координатами.
  • Звуки конвертуються в OGG формат.
  • 3D моделі конвертуються у внутрішній формат движка.
  • Файли з ім'ям file.pack перетворюються з текстових у бінарні. Це добре підходить для всіляких конфіги ігри, рівнів і т.д.
При цьому складальник дивиться час зміни файла і конвертує тільки змінені файли, що помітно прискорює його роботу. Конкретно у мене складальник написаний на PHP. Можливо це не найкращий вибір, але мені так було простіше. До того ж потенційно його можна перенести на сервер для командної роботи.

Формати
Я б рекомендував використовувати такі формати:

WEBP для картинок. Навряд чи для кого-небудь цей формат буде новим. А для тих, хто чує про неї вперше – webp може зберігати зображення без втрати якості як PNG, а так само з втратою — як JPEG, однак з помітно кращою якістю, меншому вагою і з прозорістю. Ще з плюсів – можливість скейла картинки на льоту при читанні файлу. Компілюється libwebp під всі платформи без проблем.

OGG для звуків. Андроїд нативно розуміє OGG формат, а на iOS/OSX/tvOS я використовую бібліотеку Tremor (fixed-point version of the Ogg Vorbis) для раскодировки звуків в WAV і згодовування їх OpenAL. Спроби використовувати OpenAL і на андроїд успіхом не увінчалися (звуки були з затримками).

Класи та модулі
Розберемо докладніше які класи містить движок і для чого потрібні модулі?
Правило «що виносити у модуль, а що движок?» дуже просте:


Слідуючи цьому правилу, я розподілив класи наступним чином:

Движок

  • Робота з платформою. Тут відбувається ініціалізація програми, а так само передача зовнішніх подій (пауза, тачскрін, кнопки) в основний клас движка.
  • Основний клас. Тут крутиться mainloop, обробляються вхідні події (вже в універсальному вигляді незалежній від платформи), відбувається управління потоками і фоновими завданнями.
  • Робота з 2D. Висновок картинок, атласів, постэффектов.
  • Робота з 3D моделями. Завантаження моделей, рендеринг, управління шейдерами.
  • Стандартні елементи UI. Вікна, кнопки, скролинг, повідомлення.
  • Текстури. Завантаження та вивантаження текстур. Самі декодери знаходяться в модулях.
  • Вивід тексту, рендеринг SDF шрифтів.
  • Математика. Всілякі формули, матриці, кватерніони і т. д.
  • Соціалка. Відправка листів, стандартний шарінг, rate me. Самі ж соц. мережі, зібрано в модулі.
  • Читання/запис файлів.
  • Робота з UTF8 рядками.
  • Робота з мережею.
  • Музика/звуки.

Модулі

  • Соціалка
    • Facebook
    • Google Plus

    • Twitter
    • VK
  • Replay Kit (запис екрану для iOS)
  • JSON/XML
  • Декодери картинок
    • WEBP
    • JPEG

    • PNG
  • In-apps (внутрішні платежі)
  • Game Center, Google Play Services
  • Crashlytics (відслідковувати краши)
  • Branch (глибокі посилання)
  • Аналітика
    • Google Analytics
    • Game Analitycs

    • Flurry
  • Реклама
    • Appodeal
    • Chartboost

    • Fyber
    • AdColony
    • UnityAds
    • Tapjoy
    • Google Ads
    • Heyzap
    • AdToApp
У наступних статтях я детальніше зупинюся на конкретних класах і модулях, з прикладами і корисними речами. Окрему увагу хочу приділити рендерингу SDF шрифтів (Signed Distance Field) і шейдерам в грі з шапки.

Якщо якісь окремі питання, що вас зацікавили плз пишіть в каментах, додам їх у план статей.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.