Створюємо гру для WebGL з допомогою Unity 5 і JavaScript



Unity – це багатоплатформовий ігровий движок, що дозволяє створювати ігри для ПК, консолей, мобільний пристроїв і веб-сайтів. Остання версія движка (Unity 5) має можливість експорту в WebGL, завдяки чому розробники можуть легко публікувати свої ігри в вебі. Як випливає з назви, даний експортер використовує WebGL – JavaScript API для візуалізації інтерактивної комп'ютерної 3D графіки, а також asm.js – підмножина JavaScript, яке було розроблено компанією Mozilla і подавалося як «мова асемблера для веба». Більше інформації про Asm.js і WebGL для Unity і Unreal Engine доступно тут.

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

По закінченні уроку у вас вийде ось така гра (для перегляду потрібен браузер з підтримкою WebGL). Проект також доступний для скачування з репозиторію на GitHub.

Отже, почнемо.

Кілька слів про JavaScript у Unity
Говорячи про JavaScript у Unity, ми маємо на увазі щось на зразок діалекту JS під назвою UnityScript. І хоча самі фахівці з Unity називають цю мову JavaScript, більш скептично налаштовані користувачі інтернету вважають, що підтримка JavaScript в Unity – це маркетингова хитрість. Так чи інакше, потрібно відразу зробити застереження, що UnityScript не відповідає специфікації ECMAScript, і ніхто навіть не робить спроби усунути ці невідповідності.

Встановлюємо Unity
Для початку нам потрібна робоча версія Unity, скачати її можна тут. Файли установки доступні для Windows і Mac OS X. Користувачі Linux можуть запустити Unity за допомогою Wine або використовувати інший зручний спосіб.



Після установки можемо приступати. Відкриємо Unity і створимо новий 3D проект.



Налаштовуємо проект
Тепер, коли програма відкрилася, давайте коротко пройдемося по основним інтерфейсу:



  1. Зліва знаходиться панель Hierarchy. Вона показує всі елементи поточної сцени. Сцена – це візуальне відображення гри (рівня або меню). На даний момент в панелі знаходяться два елементи: Main Camera Directional Light.
  2. Панель Scene посередині відображає камеру і світло в 3D просторі.
  3. Поруч з Scene є вкладка Ігри. Там показано, як буде бачити гру гравець. Це необхідно для тестування гри в редакторі.
  4. Справа знаходиться панель Inspector, де можна змінювати налаштування елементів. Давайте подивимося, як вона працює. Спочатку виберемо Directional Light до панелі Hierarchy. Ми побачимо багато інформації про це типі світла і зможемо відключити в ньому тіні, вибравши Shadow Type: No Shadows.
  5. Внизу екрана знаходиться вікно Project, що показує файли, які ми повинні створити для гри.
Залишилося зробити ще одну річ перед початком роботи: зберегти поточну сцену. Опція File > Save Scene відкриває діалогове вікно Save Scene, що веде до папки Assets. Найпоширеніший спосіб організувати файли у Unity – використовувати підпапки. Тому додамо нову підпапку Scenes в папку Assets і збережемо там поточну сцену, назвавши її Level.unity.

Створюємо героя
Герой у нашій грі буде стрибати з однієї платформи на іншу. Якщо йому не вдасться вчасно заскочити на одну з них, він впаде у прірву і програє. Ми почнемо зі створення героя. Оскільки гра буде від першої особи, зовнішність героя не має ніякого значення, і ми можемо використати замість нього стандартну сферу. Плюс в тому, що сфера швидко створюється, та її фізичні характеристики відмінно підходять для стрибків по платформах. Додамо її, вибравши Create до панелі Hierarchy і відредагувавши наступні параметри на вкладці Inspector:

Position { X 0, Y: 2.5, Z: 0 }
Scale { X: 0.3, Y: 0.3, Z: 0.3 }

Натиснемо кнопку Play, щоб перевірити результат. На екрані повинне з'явитися 3D простір зі сферою на тлі горизонту.

Щоб сфера падала, у неї повинен бути вагу. Виходить, нам потрібно додати до неї новий компонент, натиснувши на панелі Inspector кнопку Add Component та виберіть Rigidbody. Так як ми не хочемо, щоб сфера оберталася, потрібно зафіксувати її положення за допомогою компонента Rigidbody. Для цього відкрийте Constraints та виберіть усі осі у рядку Rotation. Програйте сцену ще раз і ви побачите, що тепер сфера падає.



Щоб запобігти нескінченне падіння сфери, створимо щось на зразок платформи. Для цього додамо плоский куб зі значенням Scale.Y, рівним 0.1. Програйте сцену ще раз і переконайтеся, що сфера успішно приземляється на платформу. Але, варто зазначити, все це виглядає не дуже природно. Як же змусити сферу підстрибувати? Для цього нам знадобляться фізичні матеріали.

Наділяємо сферу фізичними властивостями
Перш за все, створимо для нашої сфери фізичний матеріал, який дозволить їй пригинатися від поверхні зіткнення. Для цього потрібно створити в папці Assets нову підпапку Materials. Всередині цієї папки створимо новий фізичний матеріал і назвемо його Bouncy_Sphere. Ось значення, які ми повинні вказати в панелі Inspector:

Dynamic Friction: 10
Static Friction: 10
Bounciness: 1
Friction Combine: Maximum
Bounce Combine: Maximum
Якщо ми додамо цей матеріал в Sphere Collider, сфера буде підстрибувати, але завжди на однакову висоту. Щоб вона підстрибувала чимраз вище, потрібно додати фізичний матеріал і для платформи. Створимо ще один матеріал під назвою Bouncy_Platform і застосуємо до нього наступні значення:

Dynamic Friction: 0.9
Static Friction: 0.9
Bounciness: 1
Friction Combine: Average
Bounce Combine: Multiply
Щоб не заплутатися, перейменуємо наш плоский куб-платформу на Platform, якшо по ньому двічі в панелі Hierarchy. Тепер, почавши гру, ви побачите, що сфера з кожним разом підстрибує вище.

Також створимо новий стандартний матеріал під назвою Platform, щоб з'явилася можливість дати платформі який-небудь колір. Створивши його, вставити колір #C8FF00 навпаки значення Albedo, а потім перетягніть цей матеріал на елемент платформи. Тепер платформа повинна стати жовтої.

Додаємо вид від першої особи
Для цього потрібно в панелі Hierarchy перетягнути камеру на сферу. В результаті камера стане дочірнім елементом сфери і буде рухатися разом зі сферою. Камері також необхідно задати деякі додаткові параметри:

Position { X 0, Y: 1, Z: 0 }
Rotation { X: 90, Y: 0, Z: 0 }
Scale { X: 2.5, Y: 2.5, Z: 2.5 }
Clear Flags: Solid Color
Background: #000
Field of View: 80.3
Крім цього додамо ліхтар в якості другого дочірнього елемента сфери. Він допоможе гравцеві мати уявлення про висоті стрибка сфери в будь-який момент гри. Параметри ліхтаря виглядають наступним чином:

Rotation { X:90, Y:0, Z:0 }
Налаштовуємо управління в грі
Наша мета – використовувати мишу або трекпад, щоб дозволити гравцеві рухати сферу в певному напрямку. З цією метою ми напишемо перший скрипт. Як і у випадку з Rigidbody, скрипт додається до елемента гри в якості компонента. У нашому прикладі ми додамо JS-скрипт під назвою InputController до камери. Так само, як ми це робили зі сценою і матеріалами, створимо в панелі Project нову папку під назвою Scripts, в якій буде знаходитися наш скрипт. Подвійний клік по новому скрипту відкриє стандартний для Unity редактор MonoDevelop. Його можна замінити на будь-який інший редактор (Unity > Preferences > External Tools), але зараз це не має ніякого значення.

Як видно, в скрипті вже є якийсь код. Перш за все, створимо кілька змінних під першим рядком з текстом #pragma strict (включає вимушене визначення типів Unity):

#pragma strict

public var Hero : GameObject;
private var halfScreenWidth : float;
private var halfScreenHeight : float;

function Start () {}

function Update () {}

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

Дві інші змінні – закриті, їм будуть присвоєні значення функції Start. Ця функція викликається лише один раз, після запуску сцени. Обом закритим змінним буде присвоєна половина ширини та висоти екрана відповідно. Для цього ми використовуємо вбудований клас Screen:

function Start () {
halfScreenWidth = Screen.width / 2;
halfScreenHeight = Screen.height / 2;
}

Єдине, що залишилося реалізувати в скрипті InputController – отримання даних про стан і пересування мишки. Для цього ми скористаємося функцією Update, яка викликається для кожного кадру:

function Update () {
var x : float = 0.0;
var z : float = 0.0;

x = ( Input.mousePosition.x - halfScreenWidth ) / halfScreenWidth;
z = ( Input.mousePosition.y - halfScreenHeight ) / halfScreenHeight;

Hero.GetComponent( HeroController ).SetPosition( x, z );
}

Кожна з двох нових змінних x і z позначає відповідну вісь. Коли ми дивимося вздовж осі y, ми бачимо горизонтальну вісь x і вертикальну вісь z. Ми будемо міняти положення сфери на цих осях в залежності від даних, отриманих з мишки. Нам знадобиться статична змінна Input.mousePosition, повертає двовимірний вектор. Вектор, нульове значення якого припадає на нижній лівий кут, повинен переміститися в нашій системі координат на середину екрану. Наступний фрагмент коду демонструє таку трансформацію координат. Нарешті, викличемо функцію setHeroPosition з обома розрахованими значеннями в якості аргументів. Ми запишемо цю функцію в новий скрипт HeroController, прив'язаний до сфери:

#pragma strict

public function SetPosition ( x : float, z : float ) {
transform.position.x = x;
transform.position.z = z;
}

Перевіримо, як працює наш код: подвигаем мишку або трекпад, щоб сфера впала з платформи.

Реалізуємо процедурне створення платформ
Для автоматичного створення платформ нам потрібно щось на зразок шаблону платформи. У Unity такі шаблони називаються префабами. Щоб створити префаб, необхідно перетягнути платформу з панелі Hierarchy в нову папку Prefabs папки assets. Префабы легко розпізнати в панелі Hierarchy по блакитному кольору. Всі платформи, за винятком першої, будуть створюватися за допомогою нового скрипту GameManager, прив'язаного до камери. Спочатку в скрипті звернемося до необхідних змінних:

#pragma strict

public var Platform : GameObject;
public var Hero : GameObject;

private var boundary : float;
private var rotation: Кватерніонів;
private var lastPlatformPosition : Vector3;

function Start () {
boundary = 1.0;
rotation = Кватерніонів.identity;
lastPlatformPosition = new Vector3( 0, 0, 0 );
}

function Update () {}

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

  1. Мінлива boundary визначає кордон осі y. Кожен раз, коли герой стрибає вище цієї позначки, повинна створюватися нова панель.
  2. Друга змінна відповідає за поворот, необхідний для створення нового екземпляра префаба. Значення Кватерніонів.identity скасовує поворот, як нам і потрібно.
  3. Мінлива lastPlatformPosition зберігає положення останньої платформи як тривимірний вектор.
Тепер зробимо так, щоб в кожному кадрі перевірялося, знаходиться сфера вище заданої межі. Якщо так, межа підвищиться і створиться новий примірник панелі:

function Update () {
if ( Hero.transform.position.y > boundary ) {
var position : Vector3;

boundary += 1.0;
position = getNextPlatformPosition();
Instantiate( Platform, position, rotation );
}
}

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

private function getNextPlatformPosition () {
var position : Vector3;

do {
position = new Vector3( Random.Range( -1, 2 ), boundary, Random.Range( -1, 2 ) );
} while ( position.x == lastPlatformPosition && position.z == lastPlatformPosition );

lastPlatformPosition = position;

return position;
}

Щоб уникнути дублювання значень координат x і z у новій панелі по відношенню до попередньої, скористаємося циклом do while. Функція Unity Random.Range допоможе нам отримати довільні значення осей x і z. У будь-якому випадку, нам потрібно, щоб їх діапазон був між -1 і 2. Нарешті, зберігаємо нове положення панелі в якості останнього і повертаємо його.

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

Насамперед потрібно перевірити, впала сфера нижче певної позначки. Для цього відредагуємо оператор if функції update в скрипті GameManager. Оператор else if буде перевіряти, чи є положення сфери нижче -2.0 одиниць. Якщо так, він викличе закриту функцію gameOver:

function Update () {
if ( Hero.transform.position.y > boundary ) {
var position : Vector3;

boundary += 1.0;
position = getNextPlatformPosition();
Instantiate( Platform, position, rotation );
} else if (Hero.transform.position.y < -2.0) {
gameOver();
}
}

Для відстеження стану гри ми скористаємося новою функцією:

private function gameOver () {
Application.LoadLevel( 'Menu' );
}

В даному випадку ми використовуємо клас Application, що дозволяє за допомогою методу LoadLevel завантажити нову сцену Menu. Для цього спочатку створимо сцену, вибравши File > New Scene, і збережемо її під назвою Menu. Потім нам потрібно додати обидві сцени у процес складання. Налаштування збірки доступні у вкладці File > Build Settings. Не закриваючи сцену з меню, натисніть кнопку Add Current і додайте сцену в налаштування збірки. Повторіть те ж дію з відкритою сценою рівня. Тепер по завершенні гри у вас на екрані буде з'являтися тільки що створена сцена з меню гри.

Додаємо кнопку для початку гри
Щоб у гру можна було пограти, потрібно додати в меню кнопку для її запуску. Тому повернемося до налаштувань сцени меню гри і змінимо насамперед параметри камери в панелі Inspector:

Clear Flags: Solid Color
Background: #000
Width: 200
Height: 60
Щоб додати кнопку, ми скористаємося елементами інтерфейсу Unity, які можуть бути додані як 3D елементи через панель Hierarchy. Після додавання кнопки інтерфейсу Hierarchy повинні з'явитися наступні елементи: EventSystem Canvas разом з дочірнім елементом Button та його дочірнім елементом Text.

Canvas – це контейнер для всіх елементів інтерфейсу, його можна зробити в деякому сенсі адаптивним. Для цього потрібно в панелі Inspector переключити налаштування Canvas Scaler: UI Scale Mode Constant Pixel Size Scale With Screen Size. Тепер можна змінювати положення кнопки:

Rect Transform { Pos X: 0, Pos Y: 0, Pos Z: 0 }
Rect Transform { Width: 200, Висота: 60 }
Прибравши початкове зображення кнопки і виставивши її колір на #C8FF00, ми додамо меню трохи більш пристойний вигляд. Тепер поміняємо текст в елементі Text на PLAY PREJUMP і виставимо шрифт 16-го розміру. Щоб кнопка запрацювала, скористаємося новою функцією, яку ми додамо в новий скрипт UIController для елемента Button. Скрипт складається всього з однієї функції, загружающей сцену рівня:

public function StartGame () {
Application.LoadLevel( 'Level' );
}

Цю функцію можна застосувати в опціях кнопки в панелі Inspector. У налаштуваннях компонента Button (Script) можна зробити так, щоб функція виконувалася, коли користувач клікає даний компонент. З цією метою ми додамо нову функцію до події On Click (), натиснувши іконку +. Тепер можна перетягнути саму кнопку на полі введення. Потім виберемо тільки що написану функцію з скрипта UIController (UIController.StartGame).



Публікуємо проект як браузерну гру для WebGL
З Unity ви можете експортувати ваш проект як додаток для WebGL. Відкрийте налаштування збірки і виберіть WebGL в якості платформи. Потім підтвердіть вибір, натиснувши кнопку Switch Platform. Після цього залишається тільки натиснути кнопку Build та вибрати назву для гри. По завершенні складання відкрийте html-файл за допомогою будь-якого браузера, що підтримує WebGL.



Подальші кроки
Звичайно ж, нашу невелику гру можна поліпшити. Приміром, додати підрахунок очок, різні типи платформ, додаткові методи введення, звуки і так далі. Головне, що ми побачили в даному уроці, це те, що багатоплатформовий ігровий движок Unity надає хороше поєднання WYSIWYG-редактора і можливостей скриптів, створюваних на схожому на JavaScript мовою. Залежно від конкретних вимог проекту, Unity може стати гідною альтернативою WebGL-фреймворкам.

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

0 коментарів

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