Всем привет. Я работаю над игровым проектом.
Требовалось внедрение сундуков.
Каждый, кто играл в игры, так или иначе сталкивался с сундуками.
Они открыли их.
Выпавшие награды были собраны.
Как это реализовано? Так как мне нужно было реализовать в общем-то не новую механику, я начал много спрашивать и искать подходящие варианты.
Меня интересовало буквально все.
От возможности создания сервера до того, как пользователь будет получать вознаграждение.
Возможно я очень плохо искал и/или еще плохо гуглю, но достаточного описания и пояснений механики сундуков я не нашел.
Сталкивались ли вы с такой механикой? Как они реализуются? Пришлось пойти пытать геймдизайнеров, чтобы понять, чего они хотят от сундуков.
Вырисовалась следующая картина — геймдизайнеры хотят создать сундук и наполнить его различными наградами, такими как золото, артефакты, драгоценные камни.
Вознаграждения могут быть обязательными, а могут и не быть обязательными.
В сундуке может быть несколько золотых наград, но выпадут они с разным шансом.
И это только начало того, чего хочет наша Госдума.
Ладно, сундуки отошли на второй план.
И нам нужно было решить, как создавать награды и как хранить их в базе данных.
Мне бы очень хотелось сделать систему достаточно гибкой, чтобы со временем можно было добавлять новые награды или отключать определенный тип наград. Первое, что пришло в голову — сделать для каждой награды отдельную таблицу.
Классная идея, у каждой таблицы есть свой репозиторий, который извлекает данные из базы, есть сервис, который обрабатывает параметры награды и сервис для применения награды к игроку, когда он ее взял.
И все прекрасно работает до тех пор, пока не возникнет необходимость собрать сундук с наградами.
Получается, что Сундук сущности должен знать обо всех наградах в системе.
Добавление новой награды вызывает изменение сути сундука и сервисов, открывающих этот сундук.
В целом это рабочий вариант, но принцип открытости-закрытости говорит нам, что система должна быть открыта для расширения, но закрыта для изменений.
Схема, кстати, оказалась ужасной, что говорит нам о том, что скорее всего она неправильная.
Мы ищем дальше.
Что, если мы поместим все награды в одну таблицу и добавим перечисление для определения типов наград? Мы сможем составить список наград в нашем сундуке и специальные обработчики для каждого типа наград. В этом случае у нас в конечном итоге будет огромное перечисление со всеми типами вознаграждений.
Рабочий вариант, который опять-таки приводит к системным изменениям.
Но в этом варианте вам нужно будет изменить только одно перечисление и, возможно, сервис вознаграждения, к которому придется добавить «ифчик».
Я действительно хочу начать его кодировать.
Здравый смысл взял надо мной верх, и Тимлид сдох, дав мне больше времени на изучение вопроса.
Как уйти от общего перечисления? Модели ORM содержат наследование; на моей практике это не самый популярный вариант использования ORM. Кстати, мы используем спящий режим.
Итак, вы можете сделать базовый класс «награды» с набором стандартных полей.
Другие типы наград будут унаследованы от этого класса, например, награды в виде золота и драгоценных камней.
Каждая из этих наград может иметь определенные поля, которые потребуются только для этой награды.
Hibernate дает нам выбор.
Мы можем поместить все поля в одну таблицу, и для награды, которая не требует никаких полей, они будут просто заполнены нулевыми значениями.
Либо можно создать отдельную таблицу для каждого конкретного вида награды, и при сохранении награды hibernate будет извлекать основные поля из общей таблицы, а конкретные поля из дополнительной таблицы, специально созданной для этой награды.
Эта опция позволяет добавлять в систему новые награды без изменения текущего кода.
Да, схему базы данных естественно придется менять, но ни один из описанных выше вариантов без этого не обходится.
Также каждая награда будет возвращать свой уникальный тип, который нам понадобится в дальнейшем.
Отлично, награды удобно расположены в базе данных.
Но каждая награда имеет свой уникальный тип расчета.
Некоторые награды могут иметь шанс выпадения, а другие имеют ограничение по времени.
Как все рассчитать достаточно гибко? Вы можете попробовать добавить к каждой сущности метод, который будет рассчитывать текущее вознаграждение и преобразовывать его в определенный тип.
Получается, что каждая награда сможет рассчитываться сама, исходя из своих параметров.
Звучит довольно запутанно и сложно, но в коде все гораздо понятнее.
Примерно так выглядит метод, который будет иметь каждая сущность.
И один из вариантов реализации этого метода за золотое вознаграждение:List<?> rewardFor(Profile profile, ContentGenerator contentGenerator);
@Override
public List<?> rewardFor(Profile profile, ContentGenerator contentGenerator) {
int count = contentGenerator.generateCount(this.getMinCount(), this.getMaxCount(), this.getCount());
return List.of(new GoldCurrency(profile, count));
}
На бумаге у нас есть механизм расчета каждой награды в системе.
Остается только применить эту награду к профилю игрока.
Нам понадобятся процессоры, которые принимают DTO рассчитанного вознаграждения и применяют эти данные к профилю игрока.
Упомянутый выше тип награды позволит нам определить тип перехватчика.
Этот механизм позволил создавать и применять вознаграждения.
Также стало понятно, что сундук по сути тоже является наградой, в которой содержится список наград. Если генеральный директор захочет добавить награду за артефакт, ему останется только добавить новую сущность и механизм применения этой награды к профилю.
В следующей статье я подробнее и с примерами кода покажу, что я сделал.
Мне правда невероятно интересно, как в вашей компании реализован механизм вознаграждения? Насколько это гибко и удобно? Будет здорово услышать ваше мнение о том, что я сделал.
Теги: #Разработка игр #сервер #Дизайн игр #Программное обеспечение #api #gamedev #разработка игр #java #разработка #архитектура #hibernate #software #orm
-
Фейерверк
19 Oct, 24 -
Научно-Популярные Фильмы О Физике
19 Oct, 24 -
Облачная Музыка Из Ubuntu One Для Android
19 Oct, 24 -
Внедрение Формул Excel В Документы Google
19 Oct, 24