Второй девлог \ o / Ура!

Я планировал опубликовать его 21.04.21 (два дня назад), но я занялся каким-то личным делом, и мне нужно было отложить его на сегодня.

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ. В этом журнале разработчиков я должен рассказать много вещей о программировании. Если вам не нравится это видеть, ничего страшного, просто переходите к тем частям, которые вам нравятся. В зависимости от того, какой будет эта статья после того, как я закончу, я могу отделить кодирование от последующих журналов разработчиков на отдельные статьи.

Итак, давайте погрузимся в новые вещи, которые я создал.

Начальные панели HUD

Я добавил немного HUD для игры. Полоски HP, MP и выносливости теперь расположены в нижней части экрана.

Полоса выносливости (единственная, которая сейчас взаимодействует) истощается, когда персонаж бежит. Если у игрока заканчивается выносливость, он прекращает бег и блокирует кнопку (предотвращая начало спринта при минимальном значении выносливости).

Некоторые ошибки возникли из-за того, как я это закодировал:

  • Если я нажимаю кнопку спринта (сдвиг) и не двигаю своего персонажа, выносливость истощается, как будто я двигаюсь.
  • Если персонаж сталкивается с заблокированной областью, а я все еще нажимаю кнопку спринта, его выносливость также истощается.

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

Создание некоторых спрайтов

На этой неделе мне доставили планшет для рисования, и я начинаю к нему привыкать. Первый спрайт, который я сделал, был костровым (представлен на видео).

Следующим будет спрайт-лист со 100 иконами мечей (10x10 спрайтов размером 32x32) для инвентаря и добычи. Пока что чувствую себя неплохо с результатом.

Кричит для канала Adam C Younis, на котором есть много уроков по пиксельному искусству. Костер разожгли с его помощью.
Моей следующей задачей будет создание правильного набора тайлов для лесной местности, чтобы с его помощью изменить внешний вид стартовой комнаты (для этой работы я купил плиточника и надеюсь поэкспериментировать с ним. это скоро) и добить минимум 20–25 мечей.

Двуручная анимация движения персонажа

Анимация персонажа, держащего двуручное оружие / инструмент, настроена на Aseprite! Сначала я использую спрайты Sepiel. Идея состоит в том, что, когда наступит будущее, я изменю облик всех имеющихся у меня ассетов, и, возможно, базовый персонаж тоже будет изменен.
Однако я делаю вид, что использую этот спрайт как основу для рисования будущих итераций.

Новый код очереди и процессора на World Server

Теперь о «скучных» вещах (в кавычках, потому что мне очень нравится эта часть), которые касаются программирования мирового сервера и исправления некоторых проблем.

В последнем журнале разработчиков я использовал модуль узла под названием bee-queue для обработки очередей, созданных и обрабатываемых в redis. Это приводило к нескольким ошибкам, связанным с конкретной ошибкой авторизации с помощью очереди redis. Я перепробовал множество решений в Интернете, но ни одно из них не устранило проблему.
Еще одна вещь, которая способствовала изменению кода очереди, заключалась в том, что этот модуль не позволяет использовать ioredis в качестве клиента redis, и я застрял на использовании node-redis, в котором много причуд реализации, которые мне не нравятся.

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

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

Класс очереди

Класс очереди будет объектом, который будет в памяти сервера, который сохраняет интерфейс для взаимодействия с клиентом redis. В Redis каждая очередь является типом данных LIST, что означает, что я могу добавить в нее любое количество заданий (объектов, которые будут обрабатываться).
Этот класс является наследником собственного класса EventEmitter, который заставляет его генерировать события (да) для любого подписчика, которого я хочу.

В классе есть статический метод create, который создаст экземпляр этого класса и выделит клиент redis по переменной _client, если он не был определен в момент создания очереди. Этот шаблон гарантирует мне, что во всех моих очередях будет использоваться только один клиент (соединение) Redis. Возможно, это не лучший сценарий, но я хотел бы сначала попробовать это, а потом, если у меня возникнут проблемы с производительностью из-за переполненных соединений, я изменю его.

Наконец, экземпляр этого класса будет иметь методы pop, push и process. Метод pop удаляет самую старую запись о задании (очередь - это тип данных FIFO), а метод push добавляет запись о задании на последнюю позицию очереди. Таким образом, я как бы гарантирую *, что задания обновления позиции в очереди POS_UPDATE_Q будут вставлены и удалены из очереди в хронологическом порядке. .

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

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

Класс процессора

Класс процессора работает с классом очереди для обработки заданий через определенные промежутки времени.

Большинство MMORPG работает с концепцией «серверных тиков», то есть интервала, в течение которого сервер обрабатывает клиентские пакеты. Я использую интервал 100 мс, поэтому идея состоит в том, что процессор выбирает все задания, добавленные в интервале 100 мс своей очереди, и обрабатывает их.

Экземпляр процессора должен вести себя при обработке: на основе событий и интервалов. При создании такого экземпляра я могу определить queue объект, к которому этот процессор будет присоединен, функцию processHandle, которая будет использоваться для обрабатывать задания из очереди и interval в миллисекундах, которые процессор будет отмечать и извлекать задания (по умолчанию 0).

Если interval равно 0, процессор будет использовать поведение на основе событий, при котором будет подписываться событие на объект очереди и обрабатывать задания, когда он генерирует job pushed событие, мгновенно обрабатывая, когда задание добавляется в очередь.

Если interval больше 0, это означает, что мне нужна обработка тиков, и экземпляр процессора будет использовать поведение на основе интервала, которое вызовет метод start.

Этот метод установит всю среду для работы интервального процессора. Сначала он проверяет, запущен ли уже процессор, а если нет, он настраивает setInterval встроенную функцию javascript, чтобы функция запускалась за interval миллисекунд. Функция - это метод runIntervalProcess, который внутри него заставит всю бизнес-логику обрабатывать все задания внутри временного окна.

У меня также есть метод stop, чтобы остановить поведение интервала и очистить функцию интервала, установленную в движке NodeJs.

О, приятно упомянуть. Помните ошибку сборщика мусора, о которой я упоминал в предыдущем журнале разработки? Из-за этих новых объектов очереди и процессора у меня больше не было этой ошибки, так что я поднимаю палец вверх \ o /!

Клиентские и пользовательские вложения

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

Чтобы проверить, присоединить и отсоединить клиента от пользователя, я использую UUID, сгенерированный для каждого клиента в памяти, сохраняемый в записи пользовательской базы данных, переданный через внутренний запрос, сделанный с World Server на Rest Server. Этот UUID является ключом записи Redis и используется для поиска с помощью функции filter по списку клиентов.

Вот правила, по которым это работает эффективно:

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

К настоящему времени клиент успешно подключается и отключается от пользователя, но проверка все еще содержит ошибки.

Состояние ума

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

Мотивация

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

Вот и все. Спасибо, что дочитали до этого места, и увидимся в следующем журнале разработчика.