Статьи

Создание игры WebGL с Unity 5 и JavaScript

Эта статья была рецензирована Нильсоном Жаком Коллинзом , Марком Таулером и Мэттом Бернеттом . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

Unity — кроссплатформенный игровой движок, используемый для разработки видеоигр для ПК, консолей, мобильных устройств и веб-сайтов. Последняя версия (Unity 5) поставляется с экспортером WebGL, что означает, что разработчики могут с легкостью публиковать свои игры в Интернете. Как следует из названия, экспортер WebGL использует WebGL , JavaScript API для рендеринга интерактивной трехмерной компьютерной графики и asm.js , разработанного Mozilla подмножества JavaScript, которое рекламируется как «язык ассемблера для Интернета». Вы можете прочитать больше об Asm.js и WebGL для Unity и Unreal Engine здесь .

В этом уроке я собираюсь показать вам, как начать работу с Unity. Я также покажу вам, как создать простую игру в Unity с использованием JavaScript и как экспортировать вашу игру в Интернет.

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

Итак, начнем …

Слово о JavaScript в Unity

Когда мы говорим о JavaScript в Unity, мы на самом деле говорим о UnityScript, который является чем-то вроде типизированного JS-диалекта. Сами Unity часто ссылаются на этот JavaScript , но все больше циничных наблюдателей считают, что «Unity делает JavaScript» — это что-то вроде маркетинговой уловки . В любом случае, мы должны понимать, что UnityScript не соответствует какой-либо спецификации ECMAScript — и не пытается это делать. Вы можете найти хороший обзор различий здесь .

Установка Unity

Чтобы начать этот урок, нам нужна работающая версия Unity, которую можно скачать здесь . У Unity есть установщики для Windows и Mac OS X. Пользователи Linux могут запускать Unity через Wine , но ваш пробег может отличаться.

Стандартный диалог установки Unity

После установки мы готовы! Итак, давайте откроем Unity и создадим новый 3D-проект.

Диалог создания проекта позволяет нам задать имя проекта и изменить путь, по которому проект будет сохранен.

Настройка проекта

Как только Unity откроется в первый раз, нам потребуется минута, чтобы обойти главное окно:

Стандартный редактор Unity

  1. Крайняя левая панель — это Иерархия , которая выделяет все элементы в текущей сцене. Сцена — это что-то вроде вида игры, например, уровня или меню. На данный момент должен быть элемент основной камеры и элемент направленного света .
  2. Посередине вид сцены , иллюстрирующий камеру и свет в трехмерном пространстве с иконками.
  3. Рядом с вкладкой Scene есть вкладка Game , показывающая саму игру так, как ее видит игрок. Это сделано для тестирования игры в редакторе.
  4. Справа находится панель « Инспектор» , в которой можно изменить настройки элемента. Давайте попробуем это, нажав на Направленный свет в Иерархии . Теперь мы должны увидеть много информации об этом свете и иметь возможность отключить его тени с помощью Shadow Type: No Shadows .
  5. Внизу находится окно Project , в котором отображаются файлы, необходимые для разработки нашей игры.

Теперь, когда мы знакомы с интерфейсом Unity, осталось сделать одну вещь, прежде чем начать разработку: сохранить текущую сцену. Файл> Сохранить сцену открывает диалоговое окно Сохранить сцену, которое приводит к папке с именем Assets . Один из распространенных способов организации файлов в Unity — использование подпапок. Поэтому добавьте новую папку в папку Assets именем Scenes и сохраните сцену в этой папке с именем Level.unity .

Создать героя

Наша игра будет состоять из героев, прыгающих все выше и выше от платформы к платформе. Если он пропустит один и забывается, игра будет проиграна. Итак, начнем с создания героя. Поскольку игрок увидит игру от первого лица, внешний вид героя не имеет большого значения, и мы можем использовать стандартную геометрию сферы. Преимущества сферы в том, что она может быть создана за несколько шагов и подходит для физики, необходимой для прыжков. Добавьте сферу, нажав Создать в иерархии, и отредактируйте следующие свойства с помощью Инспектора:

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

Сфера с редактируемыми свойствами

Давайте проверим, что мы сделали, нажав кнопку воспроизведения. Мы должны увидеть сферу в трехмерном пространстве перед горизонтом.

Чтобы герой упал, ему нужно набрать вес. Таким образом, нам нужно добавить компонент в сферу, нажав соответствующую кнопку в Инспекторе и выбрав Rigidbody . И поскольку мы не хотим, чтобы герой вращался, мы замораживаем его в компоненте Rigidbody , открывая Ограничения и выбирая все оси в ряду Вращения . При повторном воспроизведении сцены мы должны наблюдать за падением героя.

Добавление компонента Rigidbody

Чтобы спасти героя от бесконечного падения, мы создадим плоскую коробку, которая служит платформой. Для этого мы должны добавить куб и установить значение Scale.Y равным 0.1 . Воспроизведение сцены подтверждает, что герой благополучно приземляется на платформу, хотя я должен признать, что на самом деле это не выглядит естественно. Так как же заставить героя подпрыгнуть? Добавив некоторые физические материалы.

Сделать герой отказов

Прежде всего, нам нужно создать новый физический материал для сферы, чтобы сделать ее бодрой. Для этого создайте новую папку в папке « Assets » под названием « Materials и создайте новый физический материал. Давайте назовем это Bouncy_Sphere . Значения, которые нам нужно настроить в Инспекторе :

 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 , дважды щелкнув по нему в Иерархии . Когда мы начинаем игру сейчас, мы можем заметить, что сфера прыгает все выше и выше каждый раз.

Мы также создадим новый стандартный материал под названием Platform чтобы придать платформе немного цвета. После создания этого материала используйте #C8FF00 в качестве цвета Albedo ( Albedo — это метка в пользовательском интерфейсе Unity), а затем перетащите этот материал на элемент платформы. Теперь он должен быть желтым.

Добавить перспективу от первого лица

Чтобы добавить перспективу от первого лица, мы перетаскиваем камеру (в Иерархии ) на сферу. Это сделает камеру дочерним элементом героя и заставит камеру следовать за сферой во время движения. Свойства камеры также должны быть настроены на:

 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, скрипт добавляется в элемент игры как компонент. В нашем случае мы добавим скрипт JavaScript с именем InputController на камеру. Также, как и в случае со сценой и обоими материалами, мы должны создать новую папку с именем « Scripts на панели « Проект» . Это должно содержать скрипт. Если дважды щелкнуть новый скрипт, Unity откроет его в редакторе по умолчанию MonoDevelop . Редактор по умолчанию может быть изменен на любой редактор ( Unity> Preferences> External Tools ), но это сейчас не важно.

Как вы увидите, скрипт уже содержит некоторый код. Прежде всего, мы должны создать некоторые переменные после строки 1, #pragma strict (что в контексте Unity принудительно вводит типизацию).

 #pragma strict public var Hero : GameObject; private var halfScreenWidth : float; private var halfScreenHeight : float; function Start () {} function Update () {} 

Первая переменная является публичной и имеет тип GameObject ; оно должно ссылаться на сферу. Переключаясь обратно в Unity с выбранной камерой, мы видим эту общедоступную переменную рядом с полем ввода с пустым значением. Давайте перетащим сферу в этот слот и назначим значение переменной.

Обе другие переменные являются частными и им будут присвоены их значения в функции Start . Эта функция вызывается один раз, после запуска сцены. Обе закрытым переменным будет назначена половина текущей ширины и высоты экрана соответственно, для чего мы используем встроенный в Unity класс 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. Чтобы создать префаб, нам нужно перетащить платформу из Иерархии в новую папку assets , которая (в соответствии с нашим соглашением об именах) называется Prefabs . Сборные могут быть распознаны в Иерархии по их синему цвету. Все платформы (за исключением первой) будут созданы с помощью нового скрипта под названием GameManager , который прикреплен к камере. Мы запускаем этот скрипт, ссылаясь на необходимые переменные:

 #pragma strict public var Platform : GameObject; public var Hero : GameObject; private var boundary : float; private var rotation: Quaternion; private var lastPlatformPosition : Vector3; function Start () { boundary = 1.0; rotation = Quaternion.identity; lastPlatformPosition = new Vector3( 0, 0, 0 ); } function Update () {} 

Нам нужно сослаться на готовую панель и сферу, поэтому оба должны быть перетащены в соответствующие слоты в редакторе. Мы также создаем три приватные переменные, которые будут использоваться для создания экземпляра сборной панели:

  1. Граница обозначает ограничение по оси Y. Всякий раз, когда герой прыгает выше этого уровня, должна быть создана новая панель.
  2. Вторая переменная — это поворот, необходимый для создания префабов. Значение Quaternion.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 while. Функция Unity Random.Range является правильным способом получения случайных значений для значений x и z . В обоих случаях мы хотим, чтобы они были между -1 и 2. Наконец, мы сохраняем новую позицию как последнюю позицию панели и возвращаем ее.

Добавить игровое меню

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

Сначала давайте проверим, падает ли герой ниже определенной точки. Для этого давайте отредактируем оператор if в функции update скрипта GameManager . Оператор else if проверит, находится ли y-позиция сферы ниже -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' ); } 

Здесь мы используем класс приложения Unity, который дает нам доступ к методу LoadLevel который мы можем использовать для загрузки новой сцены с именем Menu . Чтобы заставить этот код работать, мы сначала должны создать сцену через File> New Scene, а затем сохранить ее с именем Menu . После этого нам нужно добавить обе сцены в процесс сборки. Настройки сборки можно открыть в меню «Файл»> «Настройки сборки» . Сцена меню все еще должна быть открыта, поэтому давайте нажмем кнопку Add Current , чтобы добавить сцену в настройки сборки. Повторите это действие с открытой сценой уровня. Теперь, когда мы закончим игру, мы должны перейти на вновь созданную сцену игрового меню.

Добавить кнопку для запуска игры

Чтобы сделать игру доступной, нам нужно создать игровое меню с кнопкой воспроизведения. Давайте переключимся на игровое меню и сначала изменим настройки камеры в Инспекторе, чтобы:

 Clear Flags: Solid Color Background: #000 Width: 200 Height: 60 

Чтобы добавить кнопку, мы используем элементы пользовательского интерфейса Unity, которые можно добавлять как трехмерные элементы через иерархию . После добавления кнопки пользовательского интерфейса мы должны увидеть следующие новые элементы в иерархии :

  • элемент EventSystem и
  • элемент Canvas с
  • дочерний элемент Button и
  • его дочерний элемент Text .

Холст — это контейнер для всех элементов пользовательского интерфейса, и его можно сделать адаптивным. Для этого нам нужно изменить настройку Canvas Scaler: UI Scale Mode в Инспекторе с Постоянного размера пикселя на Масштабирование с размером экрана . Теперь мы можем изменить положение кнопки:

 Rect Transform { Pos X: 0, Pos Y: 0, Pos Z: 0 } Rect Transform { Width: 200, Height: 60 } 

Удаление исходного изображения кнопки и установка цвета #C8FF00 сделают меню немного приятнее. Наконец, мы изменим текст, отредактировав текст элемента «Текст» на «PLAY PREJUMP» и установив размер шрифта 16. Чтобы кнопка работала, мы будем использовать новую функцию, которую добавим в новый скрипт UIController на кнопке элемент. Он состоит из одной функции для загрузки уровня сцены:

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

Мы можем применить эту функцию в настройках инспектора кнопки. В настройках компонента Button (Script) мы можем выполнять функцию всякий раз, когда игрок щелкает ее. Для этого мы добавляем новую функцию в событие On Click () , щелкая значок + . Теперь мы можем перетащить саму кнопку в поле ввода. Затем мы выбираем только что написанную функцию из скрипта UIController.StartGame ( UIController.StartGame ).

Финальная игра

Опубликуйте свой проект как браузерную игру WebGL

Unity может экспортировать проект как приложение WebGL. Открыв настройки сборки, мы выбираем WebGL в качестве платформы. Затем мы переключаем место экспорта, нажав кнопку « Переключить платформу» . После этого нам просто нужно нажать кнопку Build и выбрать название для нашей игры. Когда процесс сборки завершится, мы можем открыть html-файл с помощью браузера для настольных ПК с поддержкой WebGL.

Переключение платформы на WebGL в настройках сборки

Куда мы идем отсюда?

Конечно, эта маленькая игра может быть улучшена, например, с помощью партитур, большего количества типов платформ, дополнительных методов ввода, аудио и так далее. Но в этом уроке мы увидели, что кроссплатформенный игровой движок Unity предлагает комбинацию WYSIWYG-редактора и возможностей сценариев, которые мы можем использовать с языком, похожим на JavaScript. В зависимости от требований нашего конкретного проекта, Unity может быть хорошей альтернативой средам WebGL.

Используете ли вы Unity в своих проектах? Вы использовали Unity для создания классной игры, которой бы вы хотели поделиться? Позвольте мне знать в комментариях ниже.