Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. 3D Games
Gamedevelopment

Создание простого бесконечного 3D раннера с использованием Three.js

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Dmitriy Sirosh (you can also view the original English article)

Final product image
What You'll Be Creating

В последнее время веб-платформа значительно выросла благодаря использованию HTML5, WebGL и увеличению мощности устройств нынешнего поколения. Теперь мобильные устройства и браузеры способны доставлять высокопроизводительный контент как в 2D, так и в 3D. Популярность JavaScript (JS) как языка сценариев также стало определяющим фактором после исчезновения веб-платформы Flash.

Большинство веб-разработчиков уже знают, насколько сложна экосистема JS с различными доступными фреймворками и стандартами, которые могут сбить с толку новых разработчиков. Но когда дело доходит до 3D, благодаря разработчику Mr.Doob, выбор однозначен. Его библиотека Three.js в настоящее время является лучшим вариантом для создания высокопроизводительного 3D WebGL-контента. Другая мощная альтернатива - фреймворк Babylon.js, который также может быть использован для создания 3D-игр.

В этом уроке вы научитесь создавать простой бесконечный 3D раннер с использованием мощного фреймворка Three.js. Вы будете использовать клавиши со стрелками для управления снежным комом, который катится по склону горы, для того чтобы уклоняться от деревьев на его пути. Арт не задействован, и все визуальные эффекты создаются в коде.

1. Базовая 3D-сцена

На Envato Tuts+ уже есть несколько руководств, которые помогут вам начать работу с Three.js. Вот некоторые из них, для старта.

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

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

Для рендеринга renderer необходимо активировать свойство shadowMap, а для сцены необходимо включить освещение активировав свойство castShadow, а всем 3D-объектам необходимо соответствующим образом установить свойства castShadow и receiveShadow. Для правильного затенения мы должны также использоватьMeshStandardMaterial или более многофункциональный материал для наших 3D-объектов. Камера управляется с помощью изящного скрипта OrbitControls. Прежде чем приступить к обучению я бы порекомендовал поиграться с основной трехмерной сценой, добавить больше примитивных фигур или поиграться с освещением и т. д.

2. Концепция бесконечного раннера

Существует много видов игр в жанре бесконечных раннеров, а наша - это "бесконечный роллер". Мы создадим игру, в которой снежный ком катится по бесконечному склону горы, где мы будем использовать клавиши со стрелками, чтобы избежать столкновения с деревьями. Один интересный факт заключается в том, что эта простая игра не будет задействовать какой-либо арт вообще, поскольку все компоненты будут созданы используя программный код. Здесь вся игра полностью, в которую вы можете попробовать поиграть.

3. Компоненты игры

Основными компонентами или элементами игры являются:

  • катящийся снежный ком
  • случайным образом сгенерированные деревья
  • прокрутка земли
  • появляющийся туман
  • эффект столкновения

Мы подробно рассмотрим каждый из этих элементов в следующем разделе.

Туман

Туман fog является свойством 3D сцены в библиотеке Three.js. Это всегда удобный трюк, чтобы имитировать глубину или показать горизонт. Цвет тумана важен для правильной работы иллюзии и зависит от цвета сцены и освещения. Как видно из приведенного ниже кода, мы также установили значение clearColor средства визуализации renderer, близкое к цвету fog тумана.

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

Снежный ком

Как показано ниже, наш снежный ком представляет собой три примитивных формы DodecahedronGeometry.

Для всех трехмерных элементов в этой игре мы используем THREE.FlatShading, чтобы получить желаемый низкополигональный (low-poly) вид.

Вращающаяся гора

Вращающаяся земля с именем переменной rollingGroundSphere - это большой примитив SphereGeometry, и мы вращаем его по оси x, чтобы создать иллюзию движущейся земли. Снежный ком на самом деле ничего не переворачивает; мы просто создаем иллюзию, поддерживая вращение земной сферы, оставляя снежный ком неподвижным.

Обычная сфера будет выглядеть очень гладкой и, следовательно, не обеспечит необходимую устойчивость, необходимую для склона горы. Поэтому мы делаем некоторые манипуляции с вершинами, чтобы превратить гладкую поверхность сферы в неровную, рельефную местность. Здесь приведен соответствующий код с последующим объяснением.

Мы создаем примитивную сферу с 40 горизонтальными сегментами (sides) и 40 вертикальными сегментами (tiers). Вы можете получить доступ к элементам массива вершин через свойство массива vertices. Мы перебираем все ряды в цикле между крайними верхними и крайними нижними вершинами, чтобы выполнять наши манипуляции с вершинами. Каждый уровень геометрии сферы содержит ровно столько же sides сторон, сколько вершин, которые образуют замкнутый круг вокруг сферы.

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

В качестве второго шага мы предоставляем каждой вершине произвольную регулировку высоты, выровненную по нормали в вершине, независимо от ряда, на котором она находится. Это приводит к неровной и шероховатой поверхности. Я надеюсь, что используемая здесь векторная математика проста, если учесть, что центр сферы считается от (0,0).

Деревья

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

Для верхней части мы перебираем каждый ряд вершин и расширяем окружность вершин с последующим сокращением следующей окружности. В следующем коде показан метод blowUpTree, который используется для расширения окружности вершин, а также метод tightenTree, используемый для уменьшения следующей окружности вершин.

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

Эффект взрыва

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

Метод addExplosion добавляет 20 вершин к матрице вершин vertices в переменной particleGeometry. Метод explode вызывается, когда нам нужно запустить эффект, который случайным образом позиционирует каждую вершину геометрии. Если объект частицы видимый,DoExplosionLogic вызывается в методе обновления update, где мы перемещаем каждую вершину за пределы. Каждая вершина в объекте points рендерится как квадратный блок.

4. Геймплей

Теперь, когда мы знаем, как создавать необходимые для игры элементы, давайте перейдем к игровому процессу. Основными элементами игрового процесса являются:

  • игровой цикл
  • размещение деревьев
  • взаимодействие с пользователем
  • обнаружение столкновений

Давайте их подробно проанализируем.

Игровой цикл

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

В функции update мы вызываем метод render, который использует средства визуализации renderer для рисования сцены. Мы вызываем метод doTreeLogic, который проверяет наличие столкновений, а также удаляет деревья после их исчезновения из виду.

Снежный ком и земные сферы вращаются, в то время как мы добавляем логику случайного подпрыгивания для снежного кома. Новые деревья размещаются на его пути, вызывая метод addPathTree по истечении заданного времени. Время отслеживается с помощью объектаTHREE.Clock. Мы также обновляем счет score, если не произошло столкновение.

Размещение деревьев

Один набор деревьев помещается за пределы дороги, чтобы создать их в игровом мире используется метод addWorldTrees. Все деревья добавляются в качестве дочерних элементов для RollingGroundSphere, поэтому они будут перемещаться, когда сфера вращается.

Чтобы разместить деревья в игровом мире, мы вызываем метод addTree, передавая значения по окружности нашей земной сферы. Утилита sphericalHelper помогает найти положение на поверхности сферы.

Чтобы посадить деревья на дороге, мы будем использовать группу деревьев, которая создается при запуске с помощью метода createTreesPool. У нас также есть предопределенные значения углов для каждого пути на сфере, хранящиеся в массиве pathAngleValues.

Функция addPathTree вызывается из функции обновления, когда после посадки последнего дерева прошло достаточно времени. Она, в свою очередь, вызывает метод addTree, показанный ранее, с другим набором параметров, где дерево помещается в выбранный путь. Метод doTreeLogic вернет дерево в пул деревьев, как только оно выйдет из поля зрения.

Взаимодействие с пользователем

Мы добавляем слушатель событий в документ для поиска соответствующих событий нажатия клавиатуры. Метод handleKeyDown устанавливает значение currentLane, если нажаты клавиши со стрелками вправо или влево, или задает значение bounceValue, если нажата стрелка вверх.

В функции update, позиция нашего снежного кома по оси x медленно увеличивается, чтобы достигнуть текущей позиции currentLane при смене полосы движения.

Обнаружение столкновения

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

В нашем случае мы вычисляем расстояние между нашим снежным комом и каждым деревом, если эти объекты сближаются мы инициируем столкновение. Это происходит в функции doTreeLogic, которая вызывается из функции update.

Как вы могли заметить, все деревья, присутствующие на нашем пути, хранятся в массиве treesInPath. Функция doTreeLogic также удаляет деревья с экрана и из пула, как только они исчезают из вида, используя код, показанный ниже.

Заключение

Создание 3D-игры - сложный процесс, если вы не используете визуальный инструмент, вроде Unity. Это может вас напугать и покажется непреодолимым, но позвольте заверить вас, как только вы освоите Three.js, вы почувствуете себя более сильным и творческим разработчиком. Я бы хотел, чтобы вы продолжили исследования, используя различные физические фреймворки или системы частиц, или примеры кода.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.