Search
Write a publication
Pull to refresh

Comments 8

спасибо интересная тема, еще на wasm видел пример хорошей отзывчивости(анимация с управлением) в 3д, если Юнити поддерживает wasm поидее тоже подойдёт, классный подход, он очень прост для понимания и может решить вопрос с структурированием данных ведь всё(или почти всё) может хранится в таких блоках структур данных, по моим предположениям это отголоски толстого клиента это ближайшее расширение данного подхода (тоесть - база данных)

Спасибо за статью, тема достаточно комплексная, вечно выходят костыли.
Недавно занимался похожими проблемами, и реализовал противоположный подход.
- Вместо добавления разных реализаций в условия, можно свести все условия к одному типу переменных. То есть у нас есть словарь значений int переменных (если переменной нет, считаем, что значение 0). Таким образом нужно реализовать только проверку типа [переменная] [тип условия] [значение] - "res.hide" >= 10. К сожалению с таким способом будет дупликация переменных, потому что любые значения нужно смапить в этот список. Но логика условий во всех местах будет значительно проще.
- Для сбора этих переменных можно использовать централизованную шину. В любом месте игры достаточно сделать что-то типа GameEvents.Emit("enemy.boar.killed", 1); чтобы действие было посчитано.
В этом случае стоить разделить понятие переменной и события, у меня это описывается как список аккумуляторов - какое событие как засчитывается. Таким образом можно одно событие учитывать в нескольких переменных.
- Систему можно сделать целиком конфигурируемой, если сделать ключи переменных и событий строковыми. Это имеет смысл, если у вас и так много конфигураций. К примеру событие "игрок получил уровень" скорее будет захардкоженным, а вот "противник умер" стоит сделать настраиваемым, и тогда тогда ГД сами опишут, что новый враг - кабан, вызывает событие "кабан умер" и посчитают его в переменных "количество мертвых кабанов" и "количество мертвых врагов".
- Еще, из опыта, стоит разделять триггеры, вызывающие проверки и сами проверки. Во первых, иногда вам просто нужны проверки, например, если вы проверяете, нужно ли отобразить маркер (условия для него выполнены), это происходит при открытии окна карты, и вам нужны только проверки. Если реагировать на любое изменение переменной, это может вызвать event hell и ваши ГД сделают вам какие нибудь циклические и каскадные события. Количество триггеров стоит ограничить. Обычно это "открыто окно Х" или "битва окончена".

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

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

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

Собственно, я потому и не привел варианты работы, например с: реактивами; невозможностью положить дату и обработчики в одну ассембли; случаев, когда требуется не накопить N валюты, а добыть N валюты с начала квеста. Сюда же можно включить адаптивные триггеры проверок. В таком случае, как мне кажется, потеряется универсальность и простота материала туториала

Как вариант, PlayerState можно передавать в IsAvailable
Плюсы:
- не надо копипастить метод Init и поле _playerState в каждую имплементацию Condition
- можно сделать единый сервис проверки для разных игроков
Минусы:
- нужно иметь доступ к PlayerState в местах проверки, что не всегда удобно

Можно посмотреть на V8 для шарпов

Sign up to leave a comment.

Articles