Создание космического шутера с помощью PlayCanvas: часть 1
() translation by (you can also view the original English article)
PlayCanvas позволяет легко создавать интерактивный 3D контент для Интернета с поддержкой WebGL. Это все благодаря JavaScript, поэтому он запускается в браузере без плагинов. Это довольно молодой движок, который существует только с 2014 года, но он быстро завоевывает популярность с такими именами, как Disney, King и Miniclip, использующие его для разработки игр.
Это отличный инструмент по двум основным причинам: во-первых, это полнофункциональный игровой движок, поэтому он обрабатывает всё от графики и столкновений до аудио и даже интеграции с игровыми геймпадами/VR. (Поэтому вам не придется искать внешние библиотеки или беспокоиться о проблемах совместимости с браузерами для большинства вещей.) Во-вторых, и по моему мнению, что делает его действительно заметным - это редактор в браузере.



Если вы привыкли работать с движком Unity, редактор PlayCanvas должен выглядеть знакомым (он даже использует похожую компонентную систему для объединения функциональности). В отличие от Unity, PlayCanvas не является кросс-платформенным и может публиковать только в Интернете. Однако, если вас интересует Веб-разработка, тогда это большой плюс, так как движок сосредоточен на Интернет, что делает его очень быстрым и легким по сравнению с конкурентами.
И последнее
замечание: хотя сам движок является бесплатным с открытым исходным
кодом, онлайн редактор и инструменты доступны только для публичных
проектов. Уж точно стоит заплатить, если
вы занимаетесь коммерческой разработкой, но вы всегда можете просто
использовать его в качестве исключительно основы для написания кода, также бесплатно.
Конечный результат
Вот, что мы будем создавать:



Вы можете опробовать демо-версию.
Сам проект является общедоступным, поэтому вы можете посмотреть и/или форкнуть его на странице проекта.
Вам не обязательно иметь какой-либо опыт работы с 3D-играми, но я предполагаю, что у вас есть некоторые базовые знания JavaScript.
Создание собственного проекта с нуля
Конечный результат - это сравнительно простая демонстрация, где вы просто летаете и выталкиваете астероиды, но она охватывает достаточно основных функциональных возможностей, которые будут полезны при создании трехмерной игры. Часть 1 будет охватывать базовые настройки, работу с моделями, физической системой и средства управления камерой. В Части 2 будет рассмотрена система наведения для пуль, создание астероидов и работа с текстом.
1. Настройка проекта
Перейдите на playcanvas.com и создайте учетную запись.
После того, как вы вошли в систему, перейдите на вкладку "Projects" на панели инструментов и нажмите большую оранжевую кнопку "New", чтобы создать новый проект. Это должно вывести окно "New Project". Выберите "Blank Project" и дайте ему имя:



После этого нажмите кнопку "Create" внизу справа. Вы перейдете на страницу обзора проекта. Здесь вы можете получить доступ к настройкам и добавить соавторов. Сейчас мы просто погрузимся в проект, поэтому нажмите на большую оранжевую кнопку "Editor".
Когда вы перейдете в свой первый проект, PlayCanvas будет показывать много советов о своем редакторе. Вы можете отключить их на данный момент. К числу основных моментов относятся:
- Левая панель (Hierarchy) - это список всех объектов игрового мира. Здесь также можно добавлять, дублировать и удалять объекты из сцены.
- На правой панели (Inspector) вы можете отредактировать свойства выбранного объекта. Выбрав объект (щелкнув по нему), вы сможете задать его положение и ориентацию, либо прикрепить сценарии и компоненты.
- Нижняя панель (Assets) содержит все ваши активы. Здесь вы можете загружать текстуры или 3D-модели, а также создавать сценарии.
- В центре сцены вы можете редактировать и строить свой игровой мир.
2. Создание объекта
Чтобы создать новый объект в сцене, нажмите на маленькую кнопку в виде плюса в верхней части панели «Hierarchy»:



Примечание: можно случайно создать новый объект внутри уже существующего объекта. Это полезно для построения объектов, состоящих из нескольких частей, или которые связаны каким-либо образом. Для управления вложением можно перемещать объекты вокруг панели Hierarchy. Перетащите его на корневой объект, чтобы поместить его обратно в верхнюю часть иерархии.
В качестве примера я собираюсь создать новый блок Box и покрасить его в красный цвет. Чтобы придать ему особый цвет, мы должны создать новый материал. Вы можете сделать это на панели Assets, щелкнув правой кнопкой мыши в любом месте внутри панели или нажав на маленький значок плюса:



После создания выберите материал и дайте ему описательное имя, например «RedMaterial» (вы можете увидеть поле имени на панели Inspector).
Теперь прокрутите вниз, выберите раздел Diffuse и измените цвет:



После этого вернитесь и выберите созданный новый блок Box (либо щелкните по нему в сцене, либо на панели Hierarchy). Затем установите этот материал в свойствах блока, который мы только что создали:



И блок теперь должен стать красным! Обратите внимание: созданный вами материал может быть прикреплен ко многим объектам.
3. Добавление физики
Чтобы включить физику объекта, мы должны добавить два компонента: Rigid Body и Collision.
Добавьте Rigid Body, нажав кнопку "Add Component" на панели Inspector вашего объекта:



Убедитесь, что тип значения Type установлено Dynamic:



И таким же образом, добавьте компонент Collision.
Теперь запустите игру, нажав маленькую кнопку воспроизведения в правом верхнем углу вашей сцены. Вы должны видеть, как ваш блок падает вниз через пол! Чтобы исправить это, вам придется добавить к Rigid Body и Collision, тип значения модели Plane (плоскость), а также, убедится, что тип значения Rigid Body (твердое тело) является статическим (так, чтобы оно также не падало).
Задача: просто для удовольствия попробуйте добавить сферу и немного наклонить плоскость (либо по оси X, либо по оси Z), чтобы посмотреть, как она скатывается.
Примечание по системе компонентов
Стоит коротко рассказать о компонентной системе, поскольку это фундаментальная часть архитектуры PlayCanvas. В принципе, идея состоит в том, чтобы разделить функциональность от объектов. Самым большим преимуществом этого является способность составлять сложное поведение из более мелких модульных компонентов.
Например, если вы посмотрите на камеру в своей сцене, вы заметите, что это не специальный объект. Это просто общий объект с прикрепленным компонентом камера. Вы можете прикрепить компонент камеры к чему-либо, чтобы превратить его в камеру, или прикрепить к камере компоненты Rigid Body и Collision, чтобы превратить его в сплошной предмет (попробуйте!).
Если вам интересно, вы можете больше узнать о преимуществах и недостатках компонентных систем на странице Википедии.
4. Добавление модели
Теперь, когда вы знакомы с основами, мы можем начать собирать нашу космическую игру. Нам для работы нужно по крайней мере корабль и астероид. Существует два способа добавления моделей:
Возьмите модель из библиотеки PlayCanvas
В PlayCanvas есть магазин (чем-то похожий на Unity Asset Store), где вы можете найти и загрузить активы непосредственно в свой проект. Чтобы получить к нему доступ, просто нажмите Library в панели Assets.
Магазин очень новый, поэтому он довольно скудный, но это хорошее место, чтобы найти шаблоны или активы для экспериментов.
Я использовал актив космический корабль из магазина в качестве корабля игрока.
Загрузите свою модель
PlayCanvas поддерживает загрузку файлов FBX, OBJ, 3DS и COLLADA (DAE), но предпочитает FBX. Вы можете легко преобразовать любую 3D-модель в FBX, открыть ее в программе Blender и экспортировать в нужный вам формат.
Вы можете найти модель астероида, которую я взял на Blendswap.com. Обратите внимание, что может понадобиться оптимизировать 3D-модели перед использованием их в игре. Например, эта модель астероида содержит более 200 000 треугольников! Это может быть хорошо для специального объекта в игре, но как только я добавил более сотни астероидов в сцену, всё начало зависать. Модификатор Decimate в Blender - это простой способ оптимизации ваших моделей. Я использовал его, чтобы сократить модель астероида до 7000 треугольников, не теряя слишком много деталей.
Как только модели будут включены в ваш проект (вам может понадобиться обновиться, если вы сразу не увидите их на панели Assets), вы можете добавить их в свою сцену. Самый простой способ сделать это - просто перетащить модель на сцену:



Как и прежде, добавьте на корабль Rigid Body и компонент столкновения Collision. Один из трюков, который можно сделать со столкновением, заключается в добавлении сетки фактических объектов в качестве собственной формы столкновения. Это привело бы к идеальной пиксельной сетке столкновения, но было бы не очень эффективно. Для этой демонстрации я выбрал простой блок в качестве формы столкновения (и сферу для астероидов) и отредактировал half-extents, чтобы примерно соответствовать форме модели.
Смещение формы столкновения
Одна из проблем, с которой вы можете столкнуться при настройке форм столкновения - это невозможность ее смещения от центра. Простой способ обойти это (помимо необходимости смещения самой модели в чем-то подобном Blender перед его экспортом) заключается в создании родительского объекта с Collision и Rigid Body и дочернего объекта, который имеет саму модель. Таким образом, можно сместить модель как дочерний по отношению к родительскому элементу, содержащему столкновение Collision.
Вот так я создал демо-проект, так что вы можете посмотреть, как это сделать.
5. Изменение гравитации и параметров сцены
Поскольку наша игра происходит в космическом пространстве, нам нужно переопределить гравитацию по умолчанию. Это можно сделать в параметрах сцены. В левом нижнем углу экрана нажмите на значок шестеренки. Это откроет настройки на панели Inspector. Найдите раздел Physics и измените значение силы тяжести (Gravity):



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



Что должно добавить игре туманностей. Это также хорошее время для очистки сцены и удаления любых тестовых объектов, которые мы создали ранее.
6. Создание сценария для корабля
Вот где мы наконец-то можем написать какой-нибудь код. Система скриптов PlayCanvas - это еще одна вещь, которая должна быть знакома, если вы использовали Unity. Вы создаете скрипты, которые могут быть присоединены к любому объекту, и эти скрипты могут иметь атрибуты, они настраиваются для каждого объекта. Атрибуты сценария очень полезны и выполняют две основные функции:
- Модульность. Можно создать скрипт, определяющий способ перемещения противника с помощью атрибута скорость и повторно использовать его для разных видов врагов с разной скоростью.
- Совместная работа. Атрибуты сценария можно настраивать непосредственно в редакторе, не затрагивая код. Это позволяет дизайнерам самостоятельно выполнять настройку и настраивать значения без необходимости беспокоить программиста или копаться в коде.
Создание сценария
Перейдите на вкладку "Аssets" и создайте новый компонент Script. Это будет код поведения корабля, поэтому назовите его "Fly". Дважды щелкните по нему, чтобы открыть редактор сценариев.
Руководство пользователя PlayCanvas является очень полезным справочным материалом при написании сценариев, как и справочник по API. Авто-завершения ввода также позволяет легко определить, какие методы доступны. Начнем с того, что наш корабль будет вращаться. Введите это в функцию обновления:
1 |
this.entity.rigidbody.applyTorque(0,1,0); |
Внутри любого скрипта this
относится к самому компоненту скрипта, тогда как this.entity
ссылается на объект, к которому привязан скрипт. Таким образом вы можете получить доступ к любому компоненту, прикрепленному к объекту. Здесь мы получаем доступ к Rigid Body и применяем к нему вращающую силу.
Убедитесь, что вы сохранили свой скрипт.
Прикрепление скрипта
Прежде чем наш скрипт будет задействован, давайте подключим его к нашему кораблю, чтобы проверить, работает ли он. Для этого просто добавьте компонент скрипта для вашего корабля, а затем добавьте к нему свой скрипт "Fly". Обратите внимание, что вы можете добавить только один компонент скрипта для каждого объекта, но вы можете добавить несколько скриптов внутри этого компонента.
После запуска вы увидите, что ваш корабль вращается!
Добавление атрибута
Как уже говорилось выше, атрибуты скрипта делают наш код более гибким. Вы можете добавить его, введя это в верхней части кода, сразу после первой строки, где создается скрипт:
1 |
Fly.attributes.add('speed', { type: 'number', default:10, title:'Ship Speed' }); |
В этом случае имя сценария будет Fly
. Единственным обязательным параметром является type
.
Чтобы увидеть атрибут в редакторе, вернитесь к компоненту вашего скрипта и щелкните значок с двумя стрелками в сценарии fly. Это кнопка анализа, которая будет искать атрибуты и обновлять редактор. Теперь компонент должен выглядеть следующим образом:



Наконец, чтобы использовать значение атрибута в вашем скрипте, просто добавьте this.[attribute_name]
. Поэтому, если бы мы захотели, чтобы это была скорость вращения, мы могли бы изменить нашу строку кода на:
1 |
this.entity.rigidbody.applyTorque(0,this.speed,0); |
Примечание. Поскольку angular damping равно нулю, корабль будет продолжать вращаться быстрее до тех пор, пока применена сила. Если вы удалите силу, она сохранит свою инерцию и продолжит вращаться с той же скоростью. Чтобы изменить это, установите angular damping в компоненте Rigid Body больше нуля.
Перемещение клавишами со стрелками
Теперь мы хотим изменить скрипт так, чтобы мы могли ориентировать корабль на клавиши со стрелками. Этот наивный подход может выглядеть следующим образом:
1 |
Fly.prototype.update = function(dt) { |
2 |
if(this.app.keyboard.isPressed(pc.KEY_RIGHT)){ |
3 |
this.entity.rigidbody.applyTorque(0,this.speed,0); |
4 |
}
|
5 |
if(this.app.keyboard.isPressed(pc.KEY_LEFT)){ |
6 |
this.entity.rigidbody.applyTorque(0,this.speed*-1,0); |
7 |
}
|
8 |
if(this.app.keyboard.isPressed(pc.KEY_UP)){ |
9 |
this.entity.rigidbody.applyTorque(this.speed*-1,0,0); |
10 |
}
|
11 |
if(this.app.keyboard.isPressed(pc.KEY_DOWN)){ |
12 |
this.entity.rigidbody.applyTorque(this.speed,0,0); |
13 |
}
|
14 |
|
15 |
};
|
Вы можете сказать, что за проблема в этом скрипте? Попробуйте. Вы можете легко направить корабль, куда хотите?
Задумайтесь, прежде чем продолжать читать. Как бы вы это исправили?
Проблема в том, что мы применяем силу в глобальных координатах, не принимая во внимание, где находится корабль. Если корабль горизонтален относительно камеры, и мы поворачиваем его по оси y, когда нажимаем влево/вправо, то он вращается правильно. Но если корабль вертикален, поворот по оси у теперь представляет собой фигуру высшего пилотажа.
Одна и та же проблема может произойти, если мы попытаемся передвинуть корабль. Направление "вперед" зависит от того, где находится корабль и не может быть абсолютным.
Теперь удобно, что каждый объект имеет три вектора направления, которые мы можем использовать: вверх
, вправо
и вперед
. Чтобы повернуть влево/вправо, поворачиваем вдоль оси вверх
, а вверх и вниз мы поворачиваем вдоль правой
оси. Вверх
и вправо
относительно объекта. Исправленная версия будет выглядеть так:
1 |
Fly.prototype.update = function(dt) { |
2 |
var horizontalForce = this.entity.up.clone(); |
3 |
var verticalForce = this.entity.right.clone(); |
4 |
|
5 |
if(this.app.keyboard.isPressed(pc.KEY_RIGHT)){ |
6 |
this.entity.rigidbody.applyTorque(horizontalForce.scale(this.speed * -1)); |
7 |
}
|
8 |
if(this.app.keyboard.isPressed(pc.KEY_LEFT)){ |
9 |
this.entity.rigidbody.applyTorque(horizontalForce.scale(this.speed)); |
10 |
}
|
11 |
if(this.app.keyboard.isPressed(pc.KEY_UP)){ |
12 |
this.entity.rigidbody.applyTorque(verticalForce.scale(this.speed * -1)); |
13 |
}
|
14 |
if(this.app.keyboard.isPressed(pc.KEY_DOWN)){ |
15 |
this.entity.rigidbody.applyTorque(verticalForce.scale(this.speed)); |
16 |
}
|
17 |
|
18 |
};
|
Чтобы добавить движение вперед делаем тоже самое:
1 |
if(this.app.keyboard.isPressed(pc.KEY_Z)){ |
2 |
this.entity.rigidbody.applyForce(this.entity.forward.clone().scale(-1)); |
3 |
}
|
Если движение чувствуется плохо или слишком скользит, потратьте некоторое время на настройку скоростей и коэффициентов Damping (демпфирования), чтобы движение чувствовалось правильно.
7. Управления камерой
Трудно отслеживать движущийся корабль со статической камерой. Самый простой способ заставить камеру следовать за объектом - это просто поместить камеру в качестве дочернего элемента этого объекта.
Попробуйте перетащить камеру на панель Hierarchy на свой корабль. Удобный способ настроить вид камеры - переключиться на просмотр этой камеры в сцене. Нажмите на кнопку в верхней части экрана, где написано Perspective. Это даст вам раскрывающийся список со всеми видами сцен, которые вы можете выбрать. Выберите Camera, самый нижний пункт этого списка. Это специальный вид, потому что все, что вы видите в редакторе, именно это камера будет видеть в игре.
После того, как вы установили вид камеры, обязательно вернитесь к перспективе или любому другому виду, чтобы случайно не испортить ракурсы камеры
Совет: Если в панели Hierarchy выбран объект, но не удается найти его в сцене, нажмите клавишу F. Это позволит сфокусировать представление на объекте и увеличить его. Для просмотра дополнительных сочетаний клавиш можно нажать кнопку с иконкой клавиатуры в левой нижней части экрана.
В этот момент у вас должна быть камера, следующая за вашим кораблем (настолько неподвижно, насколько это возможно).(Вы не сможете определить, перемещается ли камера, и в мире нет других объектов, поэтому попробуйте добавить некоторые объекты.)
Скрипты камеры
Камера, которая просто привязана к кораблю игрока, не очень интересна. Этот пост в блоге PlayCanvas исследует различные типы движения камеры. Простейший вариант, который мы можем реализовать - вид камеры.
Для этого сначала переместите камеру обратно на корневой объект.
Затем создайте новый скрипт под названием lookAt.
Функция обновления этого скрипта должна выглядеть так:
1 |
LookAt.prototype.update = function(dt) { |
2 |
this.entity.lookAt(this.target.getPosition()); |
3 |
};
|
И должен быть добавлен атрибут:
1 |
LookAt.attributes.add('target', {type: 'entity'}); |
Теперь прикрепите этот скрипт к объекту камеры. Нажмите кнопку Parse и установите объект корабль в свойстве Target.
Попробуйте запустить! Если все прошло хорошо, ваша камера будет оставаться на месте, но будет просто ориентироваться на корабль.
Аналогичным образом можно реализовать другие типы камер. Следящая камера, упомянутая в записи блога, идеально подходит, но я обнаружил, что она слишком вибрирует когда частота кадров немного снижается, так что для финального демо, я закончил с камерой, которая была прикреплена к кораблю в качестве дочернего объекта, но скрипт перемещает и вращает корабль.
Заключение
Не волнуйтесь, если всё это кажется немного ошеломляющими. PlayCanvas - это сложный движок с множеством наворотов. Здесь много чего нужно изучить, и держите руководство рядом - это хороший способ сориентироваться. Еще один хороший способ изучения движка, просто найти общедоступные проекты и посмотреть как они созданы.
Часть 2 начнется с создания системы наведения для пуль, а затем мы добавим какие-нибудь астероиды, чтобы в них стрелять, также добавим счетчик FPS и текст в игре. Если у вас есть какие-либо пожелания или предложения, или если что-то неясно, пожалуйста, дайте мне знать в комментариях!