Как я создал свое новое портфолио с помощью Pixi.js


Мое новое портфолио

Посмотреть сайт здесь: endigodesign.com

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

Знакомство с сайтом

Для начала давайте взглянем на главную страницу.

Здесь вам предлагается два варианта. Первый — просмотр интерактивной игры. Это похоже на виртуальную картинную галерею. Вы просматриваете виртуальный двухмерный мир и осматриваете каждый из моих проектов, представленных в виде памятников или высоких черных колонн. Вам также предоставляется возможность вернуться на традиционный сайт — который придерживается стандартных UI и UX моделей для навигации между каждым проектом и страницей «О проекте». Это подстраховка и запасной вариант для пользователей, которые спешат или не имеют устройства или сетевого подключения, чтобы получить удовольствие от игры.

Для игрового опыта вам сразу же представляется несколько уникальных персонажей, с которыми можно взаимодействовать, а также большой памятник — который вызывает модальную встроенную версию страницы моей биографии. При нажатии на каждого персонажа появляется традиционное диалоговое окно в стиле RPG. Каждый персонаж дает небольшие подсказки о том, как взаимодействовать с миром. Это возвращение к старой школе 2D игр Pokemon.

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

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

Инструменты и технологии

Когда я приступил к разработке этого сайта, я сразу понял, что хочу создать презентацию, которая выглядела бы и ощущалась как традиционная двухмерная ролевая игра сверху вниз. Кроме того, она должна была укладываться в рамки доступных API браузеров и современных веб-технологий. Учитывая это, использование элемента canvas и WebGL было само собой разумеющимся. В паре они позволяют отображать графику в 2D или 3D контексте. Для 2D это означает рисование примитивных форм, таких как прямоугольники и круги, изображений (текстур), и все это при непосредственном взаимодействии и участии конечных пользователей. В сочетании друг с другом они представляют собой основные строительные блоки игры.

Рендеринг игры

Мои ранние прототипы использовали чистый HTML и Javascript в паре с элементом canvas. Это позволило бы создать все с нуля. Однако я быстро понял, что это не подходит для презентации такого размера. Мне не хватало основных элементов разработки игр, таких как анимированные спрайт-листы, а взаимодействие оказалось довольно сложным. Вместо этого я решил использовать Pixi.js.

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

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

  • Текстуры: предварительно загруженные активы изображений, которые могут быть использованы в вашей сцене.

  • Графика: динамически отображаемые примитивы, такие как прямоугольники, дуги и т.д.

  • Спрайты/спрайт-листы: обычно состоят из одной или нескольких графических элементов или текстур. Pixi даже предоставляет анимированные спрайт-листы, используя ссылки на строки и столбцы одного изображения для анимации персонажей.

  • Взаимодействие: API Pixi предоставляет средства для прослушивания и действия на события для любого объекта сцены.
    Render Loop: стандартизированный цикл, предназначенный для обработки анимации и контроля прошедшего времени в сцене.

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

Фреймворк для веб-приложений

Далее я понял, что для создания основы сайта мне понадобятся компоненты пользовательского интерфейса и полнофункциональный каркас веб-приложения. Для этого я обратился к Svelte и Sveltekit. В сочетании они выполняют ту же роль, что и такие инструменты, как Angular, Next.js для React и Nuxt для Vue.

Я широко использовал следующие возможности Svelte и Sveltekit:

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

  • Маршрутизация: Sveltekit предоставляет отличную систему маршрутизации на основе файлов для управления навигацией по сайту и страницам.

  • Управление состоянием: которое осуществляется через Svelte writables. Хранилища данных используют модель pub/sub для потока данных.

  • Сборка и комплектация: Sveltekit был разработан на основе Vite, инструмента сборки, созданного Эваном Ю (известным по Vue). Он предоставляет очень быстрый и отзывчивый набор инструментов для создания локальных серверов, обработки горячего обновления модулей, компиляции Typescript, сборки, комплектации и многого другого.

Стиль и дизайн

Наконец, мне нужны были средства для стилизации и управления макетом и дизайном каждой страницы и компонента. Для этого я обратился к Tailwind CSS. Tailwind предоставляет полный набор полезных CSS-классов, позволяя при этом «выходить за рамки» с помощью произвольных переопределений. Это, конечно, приобретенный вкус, но инструмент, который в умелых руках может значительно повысить производительность. Он очень хорошо сочетается с библиотеками компонентов, такими как Svelte, React или Vue.

Собираем все вместе

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

Компонент Pixi

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

Примерный порядок действий выглядит следующим образом:

  1. Элемент canvas привязывается с помощью синтаксиса Svelte bind:this={elemRef}.

  2. Инициализируется приложение Pixi, которое принимает ссылку на элемент и устанавливает глобальные настройки, такие как размер дисплея.

  3. Загрузчик Pixi получает набор статических ресурсов, что позволяет обеспечить предварительную загрузку всех необходимых элементов. Его можно нажать, чтобы на экране появился индикатор хода загрузки.

  4. Когда игровое приложение полностью загружено, происходит ряд шагов…

  5. Карта мира генерируется с помощью предварительно загруженной текстуры, а затем помещается в контейнер «уровень». В этом контейнере размещается карта и все остальные объекты, такие как NPC.

  6. Затем инициализируется класс камеры, который в основном управляет положением x/y контейнера уровня в 2D пространстве мира. Более подробно я объясню это в следующем разделе.

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

  8. Множество игровых объектов, таких как столбы, npcs и существа, инициализируются и добавляются в качестве дочерних объектов в контейнер уровня.

  9. Контейнер уровня добавляется в сцену Pixi (сцена). Что, наконец, делает его видимым на экране.

  10. При загрузке я настраиваю фокус камеры так, чтобы она была сосредоточена на моем персонаже.

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

Управление камерой

Камеры представляют собой интересную проблему при рендеринге в 2D виртуальном пространстве. Если вы создавали игру на движке Unity или Godot, вы можете считать это само собой разумеющимся, так как большинство из них предоставляют эти функции в готовом виде. Pixi и canvas требуют, чтобы вы решали эту проблему самостоятельно. Один из методов достижения этой цели требует некоторой иллюзии для конечных пользователей. Ниже я привел иллюстрацию для наглядности.

Поскольку холст (красный) закреплен в пределах видимого холста страницы, он не может перемещаться. Вместо этого эффект движения камеры создается за счет перемещения содержимого, отображаемого в самой области холста. Обычно для этого создается контейнер, в котором размещается карта игрового мира (зеленый). Этот контейнер также может содержать дочерние элементы, такие как npcs, существа и здания (синий).

Вместо того чтобы маленький парень с камерой (как в Mario 64) следовал за вами по пятам, карта и ее дети действительно двигаются! Это действительно изящный трюк, который очень хорошо работает в исполнении.

В коде класс Camera просто контролирует, как далеко пользователь перетащил камеру из точки A в точку B, и устанавливает значение смещения, представленное x и y. Эти значения смещения затем считываются во время цикла анимации для обновления положения контейнера уровня.

Игровые объекты

Игровые объекты не являются неотъемлемой частью Pixi. Вместо этого они представляют собой концепцию, заимствованную из Unity. Эти объекты могут представлять собой все, что существует в вашей игре. Обычно для этого создается содержащий элемент (например, группа), включающий визуальные элементы (например, анимированный спрайт), и сопрягается с кодом, содержащим логику и правила взаимодействия объекта с миром.

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

Для реализации этого в коде обычно используется объектно-ориентированное программирование (сокращенно ООП). ООП предполагает создание структурированного класса, который описывает свойства объекта, а также содержит логику того, как он должен функционировать. Один или несколько таких классов могут быть инстанцированы для создания отдельных копий этого объекта.

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

Этот класс GameObject содержит все основные и общие свойства и функциональную логику, доступную всем объектам в моей игре. Я использую этот класс для создания всех сущностей — от NPC, крабов до даже столбов проекта. Каждый экземпляр имеет свое имя, ссылку на анимированный спрайт, координатные позиции и размеры. Они также имеют общую функциональность, используя методы класса, которые позволяют им двигаться по заданным траекториям и обрабатывать события ввода. Обратите внимание, что я не использую все функции для каждой сущности. Крабы не «говорят» в моей игре… но они, конечно, могли бы!

Вы, наверное, спросите себя, что происходит, когда вам нужны свойства или возможности, выходящие за рамки базового класса GameObject? Здесь вступает в игру еще одна ключевая особенность ООП — наследование классов. Для этого я создаю отдельный класс, который расширяет GameObject. Это означает, что он наследует все свойства и методы базового класса, но при этом позволяет вам перезаписывать или расширять функции, характерные для этого уникального типа сущностей.

Я использую это с большим эффектом с кошкой Лейлой, NPC-подобным существом, которое появляется в самом начале игры. Здесь я создаю класс кошки, который расширяет базовый класс GameObject, что означает, что она может иметь собственное имя, анимированный спрайт и вызывать такие функции, как диалоги. При этом я могу переписывать и расширять ее базовую функциональность. В данном случае объекты типа «Кошка» могут переворачивать спрайт по оси X в зависимости от положения мыши. Это заставляет ее следовать за положением курсора мыши на экране. Эта функция уникальна для кошек, ведь мы знаем, что кошки любят гоняться за мышами!

Подведение итогов

Хотя я хотел бы рассказать о многом другом, возможно, стоит приберечь это для последующих статей! Однако, если вам интересно узнать больше о том, как создавался сайт, я приглашаю вас изучить исходный код, который доступен на Github:
GitHub — endigo9740/endigo-design: Портфолио Криса Симмонса

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

А пока спасибо за чтение и, пожалуйста, наслаждайтесь сайтом!

Оцените статью
devanswers.ru
Добавить комментарий