Один из лучших способов расширить свои навыки разработчика - начать побочный проект. Побочный проект, который одинаково интересен и интересен.

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

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

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

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

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

Каждый раз, когда карта меняется, например игрок перемещается, строится некоторая структура, каналы Феникса распространяют такое событие на каждого игрока, исследующего данный мир, таким образом, синхронизируя их всех. Это будет основой многопользовательской механики. Я планирую создать несколько агентов на стороне сервера, которые будут отвечать за движение NPC, мировые события и поддержание мира «живым» различными способами.

Что касается внешнего интерфейса, я хотел написать его, используя реактивное программирование, основную концепцию библиотеки управления состоянием MobX, которую мы любим и используем каждый день в Untitled Kingdom. Приложение Frontend можно легко разделить на два основных уровня:

  • уровень данных, который представляет собой несколько хранилищ MobX, содержащих состояние карты и всех ее фрагментов.
  • холст, созданный с использованием THREE.js, который перерисовывается каждый раз при изменении состояния, определенного в уровне данных.

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

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

После получения данных плитки из серверной части плитки разделяются на небольшие группы и отправляются веб-работнику, где производятся необходимые вычисления (например, преобразование шестиугольных координат в координаты реального слова и определение высоты сторон плитки. на основе высоты соседа) и создается объект THREE.js. После этого этапа, который наиболее требователен к ЦП, эти объекты отправляются обратно в основной поток и добавляются в общую сцену THREE.js.

Есть масса вещей, которые я обнаружил «на собственном горьком опыте», в основном с точки зрения оптимизации, самые эффективные из них:

  • Гораздо эффективнее заранее объединить геометрию множества плиток, а затем создать сетку и отрендерить ее как «один» объект, чем отрисовывать их по отдельности, один за другим. Разница во времени загрузки была колоссальной.
  • Также стоит рассчитывать и рисовать только те вершины, которые будут видны в реальных ситуациях, даже если это означает создание сложных вычислений вместо использования встроенных геометрий, таких как цилиндр THREE.js.
  • Перенесите всю тяжелую работу на веб-работников. В вашем браузере все операции выполняются в одном основном потоке. Сложные операции могут даже привести к зависанию вкладки браузера. До этого я не обращал внимания на веб-воркеров, так как считал их непрактичными, в основном из-за необходимости хранить его код в отдельном файле и отсутствия косвенного доступа к объекту окна и чему-либо из основного потока. Первая проблема была легко решена с помощью worker loader in Webpack, благодаря которому стало проще делиться кодом между основным приложением и рабочими потоками веб. Второй требовал понимания того, как использовать систему сообщений для связи между основным потоком и веб-рабочими.

Я надеюсь публиковать больше обновлений и информации об этом проекте по мере его развития. Быть в курсе! ;)

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

Благодаря этому проекту я узнал, что Elixir не так страшен и труден в освоении, как кажется, исходя из первых предположений. Кроме того, я узнал массу информации о том, как работают игровые движки, как вы можете оптимизировать 3D-рендеринг, использовать сервис-воркеры для бесперебойной работы тяжелых JS-вычислений в вашем браузере и создать живое соединение на основе WebSocket между фронтенд-приложением и его API.

У вас есть проект, который связывает ваше хобби с профессиональным опытом? Если да, дайте мне знать в комментариях. В противном случае я настоятельно рекомендую вам начать его.

Вы можете просмотреть текущее состояние проекта здесь:
https://github.com/Rabsztok/HexWorlds для исходных кодов Elixir,
https://github.com/Rabsztok/HexWorldsClient для исходников интерфейса React
и https://hex-worlds-client.herokuapp.com, если вы хотите попробовать :)

Удачного кодирования!