Меню Закрити

Геймдев для початківців: знайомство з Unity

Розповідає Hugo Dolan

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

Чому Unity?

Якщо ви хочете створювати ігри

Існує дуже мало варіантів, коли мова йде про незалежну розробку ігор (Indie Game development). Є три основні варіанти, якщо ви хочете створювати ігри: Unreal, Unity або GameMaker.

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

Існує велика кількість успішних ігор, таких як “Escape from Tarkov” (шутер від першої особи), “Monument Valley” (головоломка) і “This War of Mine” (стратегія/виживання).

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

Якщо ви хочете створити UX-прототип

Оскільки Unity — просто ядро із купою рухів, анімації та 3d-рендерингу в реальному часі, він також є чудовим простором для створення повноцінних інтерактивних прототипів для вивчення взаємодії користувачів із додатком (UX).

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

Вікно редактора Unity

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

Scene View (Вигляд сцени): забезпечує розміщення та переміщення об’єктів GameObjects у сцені.

Game View (Вигляд гри): показує, як гравець побачить сцену з камери.

Inspector (Інспектор): надає інформацію про вибраний об’єкт GameObject у сцені.

Assets / Project (Акти/Проект): тут зберігаються всі заготовки, текстури, моделі, сценарії тощо.

Hierarchy (Ієрархія): дає змогу вкладати й структурувати об’єкти GameObjects у межах сцени.

Тепер ми можемо почати!

Ігрові об’єкти

Що таке GameObjects

GameObjects є основним будівельним блоком для всього в ігровому ядрі Unity. Назва розкриває суть.

Усе, що ви розміщуєте в сцені Unity, має бути загорнуте в GameObject (ігровий об’єкт).

Якщо у вас є досвід веб-дизайну, вам можете здатися, що GameObjects багато в чому нагадує елементи <div>. Надзвичайно нудні контейнери, але дуже вдалі для створення складних функціональних можливостей або візуальних ефектів.

Буквально все, від найдрібніших ефектів, камер, гравців, елементів інтерфейсу… (список не закінчується) — це GameObject.

Створення ієрархії

Як і <div> у веб-розробці, GameObject також є контейнером. Так само, як ви компонуєте <div> для створення різноманітних макетів або абстракцій, ви можете чинити й з ігровими об’єктами GameObject.

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

Безлад та ефективність

Веб-аналогія: ви маєте багато схожих елементів, які можуть динамічно генеруватися “на льоту” у відповідь на дії користувача, та хочете, щоб вони були впорядковані.

Unity-інтерпретація: у разі створення копії Minecraft у вас купа елементів у сцені, ви маєте додавати й видаляти “блоки” елементів задля продуктивності. Отож, є сенс прив’язати кожен такий блок до порожнього GameObject, оскільки його видалення знищує всі пов’язані з ним елементи.

Позиціювання

Веб-аналогія: ви хочете утримати позицію контенту, “прив’язаного”  до контейнера, а не до веб-сторінки.

Unity-інтерпретація: ви створили купу дронів-помічників, які юрмляться навколо гравця. Насправді ви не хочете писати код, щоб наказати їм супроводжувати гравця, натомість ви створюєте їх підпорядкованими GameObject гравця.

Вбудовані компоненти Unity

Модель компонент-актора

GameObjects самі по собі малокорисні — як ми бачили, це просто контейнери. Для розширення їхньої функціональності ми маємо додати компоненти, які є по суті скриптами, написаними на C# або Javascript.

Unity підтримує модель Actor Component, просто виставляйте Actor (актори) — це ваші GameObjects — і Components (компоненти) — скрипти.

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

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

Вбудовані компоненти

Вважаю, що настав час для кількох прикладів вбудованих компонентів, які надає ядро Unity Games.

  • MeshFilter дає змогу призначити матеріали 3D-сітки для GameObject.
  • MeshRender дає змогу призначати матеріали для 3D-сітки.
  • [Box | Mesh]Collider дає змогу виявляти GameObject під час зіткнень.
  • Rigidbody дає змогу реалістичному фізичному моделюванню впливати на GameObjects за допомогою 3d-сіток та виявляти події, що запускаються.
  • Light висвітлює частини вашої сцени.
  • Camera визначає вікно гравця, яке буде приєднано до GameObject.
  • Різні компоненти UI Canvas для відображення графічних інтерфейсів.

Існує більше компонентів, але це основні, із якими потрібно ознайомитися.

Підказка: можна одержати доступ до документів про них усіх за допомогою посібника Unity Manual та Scripting Reference в автономному режимі.

Просто натисніть на розділ довідки Help. Документи в цілому добре написані.

Створення користувацьких компонентів

Вбудовані компоненти керують фізичними та візуальними ефектами, але для того щоб дійсно створити гру, вам потрібно прийняти ввід користувача й маніпулювати цими стандартними компонентами, так само як і GameObjects.

Щоб почати створювати компоненти, виберіть в меню GameObject > Add Component > введіть ім’я нового компонента в панелі пошуку > new script (c#).

Узагалі кажучи, я б не радив використовувати Javascript у Unity. Він не оновлювався всіма чудовими штуками, які прийшли з ES6, а основна частина найпросунутішого  матеріалу ґрунтується на матеріалах C#, які перекладаються на Javascript. Зі свого досвіду скажу, що це просто перетворюється на довгий обхідний шлях.

Структура MonoBehaviour

Ключові функції

Усі компоненти успадковуються від MonoBehaviour Class. Сюди належать багато стандартних методів, головні з яких:

  • void Start(), який викликається, коли об’єкт, що містить скрипт, створюється в сцені. Це потрібно щоразу, коли ми хочемо виконати певний код ініціалізації, наприклад, дати спорядження гравцям після їхнього введення в гру.
  • void Update(), який викликається кожним фреймом. Ось куди спрямовується основна частина коду, яка стосується вводу користувача й оновлення різних функцій, таких як рух гравця в сцені.

Змінні Inspector

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

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

Змінні у вікні інспектора можуть бути змінені в будь-який час під час виконання або в режимі редагування.

Примітка: зміни, оголошені під час виконання, не збережуться.

Ми можемо зробити це легко, просто зробивши їх загальнодоступними змінними в тілі компонента.

Зверніть увагу, як ми можемо зробити змінні з різними рівнями доступу: індивідуальним, загальнодоступним та загальнодоступним, але не відображеним у вікні інспектора.

Дії користувача

Звісно, ми хочемо, щоб наша гра реагувала на дії користувача. Найбільш поширені способи це зробити використовують такі методи у функції Update() компонента (або будь-де за потребою):

  • Input.GetKey(KeyCode.W) повертає значення True, коли клавіша W була натиснута і не віджата.
  • Input.GetKeyDown(KeyCode.W) повертає True, коли клавіша W була натиснута вперше.
  • Input.GetAxis(“Vertical”), Input.GetAxis(“Horizontal”) повертає значення від -1 до 1 в залежності від маніпуляцій користувача з мишею.

Маніпулювання GameObjects

Звичайно ж GameObjects повинні реагувати на дії користувача. Існує декілька типів реагування:

  • Translation (передача), Rotation (обертання), Scale (масштаб).
  • Створення нових GameObjects.
  • Надсилання повідомлень до існуючих GameObjects/компонентів.

Перетворення

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

Зазначені методи цілком зрозумілі, просто зауважте, що ми пишемо з маленької літери gameObject, щоб наслідувати GameObject.

Загалом краще використовувати локальні параметри [Position, Rotation] (Позиція, Поворот), а не глобальні. Зазвичай це суттєво полегшує переміщення об’єктів, оскільки вісь локального простору буде орієнтована й зосереджена на батьківському об’єкті.

Переваги локального простору є очевиднішими з діаграмою.

Якщо вам потрібно конвертування між локальним і глобальним простором (що часто буває), можна використовувати такий підхід:

Як ви можете здогадатися, за цим натяком на “Inverse” в назві методу стоїть трохи простої лінійної алгебри.

Створення нових об’єктів GameObjects

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

По-перше, нам потрібно ввести поняття Prefab. Ми можемо їх створити, просто перетягнувши будь-який GameObject з ієрархії сцени в каталог активів (assets folder).

Вигляд попередньої збірки на вкладці “Asset” (актив)

Це по суті зберігає шаблон об’єкта, який щойно був у нашій сцені, із тими ж конфігураціями.

Прикладом користувацького об’єкта є блок, який використовується для динамічного генерування цегли Lego в сцені, він має безліч компонентів, приєднаних до нього з різними значеннями за замовчуванням.

Тепер, коли у нас є Prefab-компоненти, можемо призначити їх змінними inspector (як описано вище) до будь-якого компонента сцени, так що можемо будь-коли створювати нові GameObjects, визначені Prefab.

Потім ми можемо створити “екземпляр” Prefab і рухати його до потрібного місця в сцені та встановити потрібні “батьківські” відносини.

Доступ до інших GameObjects та компонентів

Часто нам треба встановити зв’язок з іншими GameObjects, а також із пов’язаними з ними компонентами. Коли в нас є посилання на GameObject, це досить просто.

ComponentName comp = 
some_game_object.GetComponent<ComponentName>();

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

Доступ через змінну Inspector

Це найпростіше. Просто створіть загальнодоступну змінну для GameObject, як ми раніше продемонстрували з prefab, і вручну перетягніть її на компонент через інспектора. Потім звертайтеся до змінної, як зазначено вище.

Доступ через позначення тегів

Ми можемо позначити теги GameObjects або Prefabs через інспектора, а потім використовувати функції пошуку GameObjects, щоб знайти посилання на них.

Це просто зробити, як показано нижче.

GameObject some_game_object = 
GameObject.FindGameObjectWithTag(“Brick”);

Доступ через transform (перетворення).

Якщо ми хочемо одержати доступ до компонентів у певному батьківському об’єкті, то можемо це легко зробити  через атрибут transform.

ComponentName comp = 
gameObject.transform.parent.GetComponent<ComponentName>();

Доступ через SendMessage

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

gameObject.SendMessage(“MethodName”,params); // Broadcast message
gameObject.SendMessageUpwards(“MethodName”, params); // Only received by components which are nested above.

Raycasting

Ви, може, чули про це раніше, коли порівнюють FPS-ігри “на фізиці” або “на променях”. Raycasting по суті нагадує лазерний вказівник, який після зіткнення із Collider (прискорювачем) або Rigidbody (твердим тілом) повертає “удар” та передає деталі об’єкта.

Якщо це буде потрібно, є два сценарії (можливо, їх існує й більше):

  1. Якщо ви розробляли систему зброї для гри, ви можете використати raycasting для виявлення ударів і навіть налаштувати довжину променя так, щоб елементи ближнього бою “били” лише на короткі відстані.
  2. Створіть промінь від вказівника миші до точки в 3d-просторі, якщо ви хочете, щоб користувач у стратегічній грі міг вибирати компоненти мишею.

Приклад 2 докладно розглянутий вище.

Як бачите, кодувати довелося добряче. Головне, потрібно зрозуміти, що для відправлення променя до місця, на яке миша вказує в 3D-просторі, потрібно перетворення ScreenPointToRay. Причина в тому, що камера передає 3D-простір у вигляді 2D-вікна перегляду на екрані ноутбука, тож, певна річ, існує проекція, пов’язана з перенесенням на 3D.

Виявлення зіткнень

Раніше ми згадували компоненти Collider і Rigidbody, які можна додати до об’єкта. Правилом зіткнень є те, що один об’єкт у зіткненні повинен мати твердий корпус, а інший — колайдер (або кожен має обидва компоненти). Зверніть увагу: якщо використовуєте raycasting, промені взаємодіють лише з об’єктами, до яких додаються компоненти колайдера.

Після установки в будь-який користувацький компонент, приєднаний до об’єкта, ми можемо використовувати методи OnCollisionEnter, OnCollisionStay та OnCollisionExit для реагування на зіткнення. Щойно ми одержимо інформацію про зіткнення, у нас буде GameObject, який його спричинив, та можна буде використовувати вивчене нами раніше для взаємодії з прикріпленими до нього компонентами.

Зауважимо, що тверді тіла Rigidbody наділяють об’єкти фізичними властивостями, наприклад, гравітацією, тому якщо хочете її вимкнути, потрібно перевірити, щоб  is_kinematic було увімкнено.

Перевірка is_kinematic, щоб вимкнути небажану фізику, але зберегти добре виявлення зіткнень.

Додаткові функції

Ми не будемо нічого із цього робити зараз, просто хочемо, щоб ви знали про їхнє існування.

Створення GUI’s (графічного інтерфейсу користувача)

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

Розширення редактора Unity

Unity дає змогу додавати користувацькі кнопки до ваших inspectors, щоб ви могли впливати на світ гри в режимі редагування. Наприклад, щоб будувати ігровий світ, можете розробити спеціальне вікно інструмента для побудови модульних будинків.

Анімація

Unity має анімаційну систему на основі графіків, яка дає змогу змішувати й керувати анімацією на різних об’єктах, таких як гравці, застосовуючи скелетну анімаційну систему.

Матеріали та PBR

Unity працює із фізично орієнтованим механізмом рендерингу, який забезпечує освітлення в реальному часі та реалістичні матеріали. Однак реальність така, що вам насамперед доведеться навчитися 3D-моделювання або скористатися моделями, зробленими й оптимізованими кимось іншим, перш ніж ви зможете зробити матеріал, який має реалістичний вигляд.

Поради для новачків

Якщо ви плануєте писати свою першу гру, не варто недооцінювати складність і час, потрібний для написання навіть найтривіальніших ігор. Пам’ятайте, що над більшістю ігор, які вийшли на Steam, багато років працюють цілі команди!

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

Перш ніж ви візьметеся до написання будь-якого коду для будь-якої частини вашої гри, знайдіть, що вже було зроблено раніше для вирішення такої проблеми — імовірно, вона матиме значно витонченіше розв’язання.

Корисні ресурси та спільноти

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

Concept Art (Концепт)

Feng Zhu Design School — Школа дизайну Фен Чжу (понад 90-годинний підручник із  мистецтва концепту).

Tyler Edlin Art — Велика художня спільнота BST зі зворотним зв’язком від професіоналів.

Art Cafe  — інтерв’ю та семінари з відомими художниками-концептистами.

Trent Kaniuga — ілюстратор і 2D-художник, який також розробляє свою власну гру.

3D Modelling (3D-моделювання)

CG Cookie — найкращі основи моделювання сітки в Blender, є також багато іншого контенту для Blender.

Tor Frick — моделювальники твердих поверхонь і скульптур у Blender.

Gleb Alexandrov — короткий підручник із мультиплікації в Blender.

Ігровий дизайн

DoubleFine Amnesia Fortnight — GameDevs, які виконують 2-тижневий хакатон і записують увесь процес проектування.

GameMakers Toolkit — розглядає принципи ігрового дизайну.

Програмування

Handmade Hero — написання гри та ядра з нуля на С.

Jonathan Blow — інді-розробник, який транслює свою розробку гри.

Brackeys — підручники з Nice Unity.

Якщо ви знайшли помилку, будь ласка, виділіть фрагмент тексту та натисніть Ctrl+Enter.

0

Повідомити про помилку

Текст, який буде надіслано нашим редакторам: