Спроектируйте систему квестов для мультиплеерной RPG в Unreal Engine. В игре сотни квестов с упорядоченными целями (убить N, собрать X, дойти до места), и дизайнеры должны создавать целые квесты и цели без пересборки под каждый квест программистом. Множество несвязанных игровых систем — бой, подбор, исследование — должны продвигать цели, не зная о конкретных квестах и не будучи к ним жёстко привязанными. Прогресс и завершение квеста должны быть авторитетными на сервере, а не решаться клиентским UI, и прогресс должен сериализоваться, чтобы переживать сохранение. Каждый игрок ведёт свои квесты и прогресс, а UI обновляется по изменениям прогресса, а не опросом. Опишите, как представлены квесты и цели, как игровые события продвигают цели без жёсткой связности, где живут авторитет и прогресс, и компромиссы вашего подхода.
Описывайте квесты как UQuestDataAsset с упорядоченными определениями целей; UQuestComponent ведёт активные квесты и прогресс по каждой цели. Игровые системы рассылают события, которые слушает менеджер квестов, продвигая цели и выдавая награды на стороне сервера.
- ✗Жёстко зашивать логику под каждый квест вместо модели целей на данных
- ✗Связывать игровые системы напрямую с квестами вместо шины событий
- ✗Отслеживать прогресс и завершение квеста на клиенте вместо сервера
- →Как бы вы поддержали ветвящиеся квесты со взаимоисключающими путями целей?
- →Как бы вы сохраняли прогресс квестов через вашу систему сохранений?
Ключевые классы
UQuestDataAsset— описание квеста:id, текст, упорядоченный массивFObjectiveDef, награды, предусловия.FObjectiveDef—USTRUCT: тип цели (убить/собрать/дойти), целевой тег, нужное количество.UQuestComponent—UActorComponentнаPlayerState: активные квесты, прогресс по целям, история.UQuestSubsystem— шина событий: игровые системы шлют сюда события, компоненты подписаны.FQuestProgress—USTRUCTрантайм-состояния:idквеста, индекс цели, счётчики.
Модель данных
Квест — это данные: один движок исполнения читает UQuestDataAsset. Цель описана типом и тегом, не кодом. Прогресс (FQuestProgress) отделён от описания, что позволяет сериализовать его в сохранение.
Поток данных
- Игровое событие (убийство, подбор) → система шлёт
FGameplayEventвUQuestSubsystem. - Подсистема рассылает событие подписанным
UQuestComponent. - Компонент сверяет событие с текущей
FObjectiveDef, инкрементирует счётчик. - Цель выполнена → переход к следующей; все цели выполнены → сервер выдаёт награды.
FQuestProgressреплицируется, UI обновляется по делегатуOnQuestUpdated.
Соображения по репликации
UQuestComponent на PlayerState, FQuestProgress — Replicated. Вся проверка целей и выдача наград — на сервере. Клиент только отображает реплицированный прогресс. Событийная шина работает только на сервере; UI обновляется через OnRep.
Настройка дизайнером
Каждый квест — ассет UQuestDataAsset; цели собираются из переиспользуемых FObjectiveDef в редакторе. Тексты — через таблицы локализации. Награды ссылаются на UItemDataAsset. Дизайнер делает контент без кода.
Компромиссы
- Линейный массив целей vs. граф: массив прост, граф нужен для ветвления — усложняет UI и сохранение.
- Шина событий vs. прямые вызовы: шина развязывает системы и масштабируется, но добавляет косвенность при отладке.