en uk

Як ігри (або будь-які персональні проекти) ніколи не повинні розроблятися

Ця історія про марну трату часу і життя. Ця історія про Attraction Wars.

Attraction Wars це онлайн браузерна гра, яку я розробив у вільний час.

Я оточений “історіями успіху”. Проте дуже мала кількість нових проектів (або “стартапів”, якщо вам так зручніше) стають успішними. За різними джерелами, це менше 10%, або навіть (і цій цифрі я більше вірю) менше 1%.

Звичайно, це дуже сильно залежить з якого етапу розвитку стартапи попадали в цю статистику…  Але ця історія не про це. Я просто відчув, що повинен написати “історію НЕ успіху”, просто щоб розбавити всі ці “історії успіху” іншою казочкою.

Чесно кажучи, я думаю, що історія розробки Attraction Wars - це приклад того, як ігри (або будь-які персональні проекти) ніколи не повинні розроблятися.

Однак це навчило мене багато чому, в тому числі технологіям та світогляду, тому надіюся, що цей досвід буде комусь корисним. Або ця стаття буде для мене просто як нагадування.

Якщо ви зацікавлені в зануренні у цю глибоку нору, тоді, будь-ласка, читайте далі.

1. Як народилася ідея. Геймдизайн.

Спочатку була ідея. І ідея була змоделювати Гравітаційний маневр. Чому? Тому що це здавалося крутим. (Ніт;)) Хоча на цьому етапі це ще не було неправильним.

Ідея швидко еволюціонувала в "покращений" клон agar.io.

Гравці швидко стали планетами, “їжа” - астероїдами. Гравці блукають по світу, збирають астероїди й інколи вступають у бій з іншими гравцями. Ці дії збільшують масу гравця і очки.

Після деяких роздумів як повинен працювати гравітаційний маневр, я вирішив створити 3 зони навколо гравця з різними радіусами.

Ці зони працюють коли менший гравець знаходиться в зоні впливу більшого гравця.

Найближча до гравця зона - зона простого притягування. Менші об’єкти просто притягуються до більших, сила збільшується зі зменшенням відстані.

Наступна зона - це якраз зона гравітаційного маневру. Якщо гравець попадає в цю зону, він отримує бонусну швидкість та очки.

І остання зона - це зона обертання - тут менші об’єкти обертаються навколо більших.

2. Ідея - ніщо без реалізації. Технічна сторона.

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

Я вирішив використовувати екосистему javascript просто тому, що я її вже трохи знав, і хотів покращити свої знання.

Я вибрав Phaser у якості клієнтського рушія бо я його уже трохи використовував, та і, чесно кажучи, не так уже й багато альтернатив існує для js.

Для бекенду я вирішив використати Node.js із socket.io.

Що ж, основні інструменти були вибрані і я почав реалізацію. І найперша помилка була зроблена вже на цьому етапі. Я створив два репозиторії, для клієнтської і бекенд частини. Масштаб проекту був занадто малий на цьому етапі, так що я не зміг зарані побачити проблеми в цьому рішенні.

Базова механіка поглинання, граничні умови, візуалізація та клієнт-серверна взаємодія були реалізовані доволі швидко. Кілька вечорів і я мав пародію на agar.io. Згодом я добавив статистику, таблицю рекордів, UI елементи, і т.д. Все максимум просто, і поки що без реальної графіки:

Все йшло добре.

Потім я почав реалізацію взаємодій у зонах. Зони притягування та обертання теж реалізувалися доволі швидко. Проте реалізація гравітаційного маневру була довгою, болючою і забагованою. Я потратив занадто багато часу на те, щоб відполірувати її і зробити щоб вона працювала достойно. Спойлер: вона і зараз працює погано, принаймні гірше, ніж все інше в грі.

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

Нарешті я зробив щоб ця зона просто хоч якось працювала і пішов далі.

Настав час для перших тестів з реальними користувачами. Все пройшло доволі гладко у локальній мережі і трохи пізніше через Інтернет, але я все ж побачив невеликі “лаги”, і дуже вчасно.

Розмір пакетів, якими я обмінювався між клієнтом і сервером був дуже великим. Я зміг зменшити його в сотні разів завдяки оптимізації даних (відправляти користувачам тільки релевантні дані) і використанню бінарного формату (бібліотека https://github.com/darrachequesne/socket.io-msgpack-parser дуже допомогла в цьому).

Тепер розмір пакетів, якими клієнт та сервер обмінюються кожні 30 мілісекунд близько 500 байт. Можна було б зробити ще менше, але зусилля того не варті. Я засвоїв урок  :).

Гра потроху вимальовувалася, і я став турбуватися про кращий UI, розгортання десь для публічного доступу, або хоча б для тесту обмеженою групою людей, налаштуванням процесу оновлення і багатьма іншими не дуже цікавими, але важливими речами.

У той же час моя дівчина зробила пару комітів, надзвичайно покращивши графіку:

А потім ще кілька комітів і гра отримала свою фінальну візуалізацію:

Я звернув увагу, що рендеринг на клієнті недостатньо плавний. Ця проблема виправилася дуже швидко завдяки оптимізації зображень. Я не думав, що їх розмір впливає на що-небудь, крім часу завантаження сторінки, але я помилився. Врешті я досяг 60 кадрів за секунду на більшості пристроїв, крім деяких найдешевших/старих.

Після деяких експериментів я зрозумів, що продуктивність на таких пристроях може бути трохи покращеною якщо використовувати canvas замість WebGL. Але це було не завжди так, і також я не зміг знайти надійної умови, коли треба відключити WebGL. Тож я додав чекбокс і юзер може сам це зробити при потребі.

Я готувався до першого релізу і раптом зрозумів, що онлайн гра без якоїсь початкової кількості користувачів просто не “злетить”

Рішення цієї проблеми таке несподіване):

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

І тут я зрозумів, що я уже реалізував низькорівневий клієнт, який синхронізує дані з бекендом і зберігає їх у локальні об’єкти. І що ж я мав робити? Правильно, виділити цей функціонал у п’ятий репозиторій. Тож я тепер мав фізичні границі, не було способу порушувати залежності і всяке таке (хороше). І в той же час, для того, щоб зробити якусь зміну, я мав зробити коміт одразу у кілька репозиторіїв, і тільки аж потім можна було перевірити, чи зміни дійсно робочі. Це дуже роздратовувало. Думаю тепер ви розумієте, чому “перша помилка” - то дійсно була помилка.

Прийшов час для наступного букету граблів)

Я спробував 3 різних алгоритми для реалізації ботів. Я списав блокнот формулами, як у давні добрі часи коли я ще навчався у виші) Але результат мене не задовольняв

Як ви можете бачити, я бережно заблюрив  назву компанії, яка щедро подарувала мені цей записник

Це забрало в мене близько місяця. Я писав тести, щоб перевіряти алгоритми. Навіть інтеграційні. Але все це просто не працювало коректно разом при запуску.

Не хочу втомлювати вас детальними поясненнями своїх перших алгоритмів (якби вони запрацювали, я б обов’язково поділився, клянуся ;)) Скажу тільки, що я знаходив перетини об’єктів з можливими напрямами руху, потім сортував їх по максимуму вигоди (об’єкти для поглинання) і мінімуму ймовірності бути поглинутим більшим об’єктом.

Після місяця невдалих спроб я згадав про agar.io, загуглив щось на зразок “agario bots” і пішов на porngithub в пошуках натхнення. І знайшов його! За пів години я проглянув кілька репозиторіїв і знайшов просту та красиву ідею.

Бот вибирає найближчу ціль і рухається до неї. Як тільки близько виявляється небезпека, бот змінює напрямок на 90 градусів, проходить певну відстань і знову вибирає ціль - і все спочатку. Так просто і так круто! Я добавив певне випадкове відхилення від 90 градусів щоб прибрати рідкісні “зациклення” і щоб зробити поведінку “більш живою”. І це зайняло всього один вечір після змарнованого місяця!

І це, звісно, була моя третя помилка. Я недооцінив складність завдання і самовпевнено думав, що гуглити ще не варто.
Пізніше я використав faker для генерації імен.

Згодом я потратив якийсь час на боротьбу з підтіканнями пам’яті у сервісах сервера і ботів з допомогою запуску nodejs в режимі інспекта ("node --inspect") і приєднання до Chrome dev tools.

За допомогою ботів я швидко оцінив скільки онлайн користувачів може обслуговувати сервер без зменшення продуктивності, і додав ліміт на кількість з’єднань (40 користувачів), а також систему самобалансування для ботів. Тепер вони заповнюють світ, але як тільки користувачі починають логінитися, звільняють місця для людей (до цього часу боти мені підкоряються ;) )

І… Це був фінальний реліз гри)

Віртуальний світ, наповнений штучними створіннями, які намагаються вижити і перемогти інших створінь.

3. Підведемо підсумки

То що ж я зробив неправильно? І що змінив би, якби захотів розробити цю гру знову?

1. Я використав би один репозиторій. Якби я зробив це, то було б значно простіше синхронізовувати зміни між компонентами та шерити структури даних.

2. Чіткіше усвідомлювати зусилля для втілення ідеї і не ставити занадто амбітних цілей. Це була моя всього лише друга гра, але проблема навіть не в цьому. Проблема в тому, що реалізація та достойна підтримка такої онлайн гри просто неможлива для персонального проекту з бюджетом розробки 10 годин на тиждень.

Для того, щоб зрозуміти, що було заплановано зробити, достатньо подивитися на trello board проекту: https://trello.com/b/udbODP6r/attraction-wars. Якимось дивом я закінчив MVP за 6 місяців, але реалізація решти фіч зайняла б ще не менше року. І ця оцінка не включає розробки масштабуємості, щоб можна було підключати більше 40 користувачів (ну хіба що крім найпростішого варіанту із випадковим розприділенням користувачів засобами nginx на ідентичні незв’язані ноди). 

Також щоб вважати проект на 100% готовим до публічного доступу треба реалізувати ще один дуже непростий функціонал - стійкість до мережевих затримок. А ще Андроїд версія… Думаю, ви розумієте.

3. Більше обдумати ідею та механіки. До реалізації слід приступати тільки після планування та ескізів. Це не тільки зекономить купу часу, а й також просто зробить гру кращою. Не варто витрачати час на фічі, які непомітні для користувачів, або просто не важливі.

4. Двічі подумав би перед тим, як робити онлайн гру. Це важче, ніж ви думаєте, навіть якщо ви знайомі з веб розробкою.

5. Детальніше познайомився б із ігровими рушіями, такими як Unity (я уже це зробив) або Unreal Engine. Витративши небагато часу на вивчення можна зекономити купу часу в майбутньому, і гра буде набагато кращою.

4. Ресурси, пов’язані з Attraction Wars

1. Репозиторії:

https://github.com/harentius/attraction-wars-server

https://github.com/harentius/attraction-wars-client

https://github.com/harentius/attraction-wars-client-storage

https://github.com/harentius/attraction-wars-bots

https://github.com/harentius/attraction-wars

2. Trello board:

https://trello.com/b/udbODP6r/attraction-wars

3. Сама гра:

https://aw.folkprog.net/

5. Бонусні ресурси

Я всерйоз зацікавився розробкою ігор, тож можу поділитися з чим корисним (на мою суб’єктивну думку) стикнувся за останні кілька місяців.

1. Безкоштовний курс по Unity https://learn.unity.com/course/create-with-code. Після його закінчення ви зможете робити ваші ігри на рушії Unity. Не AAA проекти, але все ж дуже достойні для інді розробки. Приклад того, що я зробив за місяць вивчення просто щоб перевірити, що я засвоїв курс: https://www.youtube.com/watch?v=sXL2hECK8KQ

2. Jesse Schell "The Art of Game Design: A Book of Lenses"- чудова книга щоб впорядкувати ваше мислення в цій сфері.

3. Scott Rogers "Level Up! The Guide to Great Video Game Design"