Внедрение систем достижений в современные сложные игры
Многие игры, которые создаются в наши дни, имеют собственную систему достижений, которая поощряет игроков / пользователей за выполнение определенных задач. Система значков здесь на stackru точно такая же.
Хотя есть некоторые проблемы, для которых я не мог найти хорошие решения.
Системы достижений должны постоянно следить за определенными событиями, придумать игру, которая предлагает от 20 до 30 достижений, например, для боя. Сервер должен был бы проверить эти события (например: игрок избегал x атак противника в этом сражении или игрок прошел x миль) все время.
- Как сервер может обрабатывать такое большое количество операций без замедления и, возможно, даже сбоев?
Системы достижений обычно нуждаются в данных, которые используются только в основном движке игры, и в любом случае они бы не потребовались, если бы не было этих неприятных достижений (подумайте, например, как часто игрок прыгал во время каждого боя, вы не хочу хранить всю эту информацию в базе данных.). Я имею в виду, что в некоторых случаях единственным способом добавления достижения является добавление кода, проверяющего его текущее состояние, в ядро игры, что обычно является очень плохой идеей.
Как системы достижений взаимодействуют с ядром игры, в котором содержится ненужная информация? (см. примеры выше)
Как они отделены от ядра игры?
Мои примеры могут показаться "безвредными", но подумайте о 1000+ достижениях, доступных в настоящее время в World of Warcraft, и, например, о множестве игроков онлайн.
4 ответа
Системы достижений на самом деле просто форма ведения журнала. Для такой системы хороший подход - публикация / подписка. В этом случае игроки публикуют информацию о себе, а заинтересованные программные компоненты (которые обрабатывают отдельные достижения) могут подписаться. Это позволяет вам наблюдать за общедоступными значениями с помощью специального кода регистрации, не влияя на логику основной игровой игры.
Возьмите пример "игрок прошел х миль". Я бы реализовал пройденное расстояние как поле в объекте player, так как это простое значение для увеличения и не требует увеличения пространства с течением времени. Достижение, которое вознаграждает игроков, которые проходят 10 миль, становится подписчиком этого поля. Если бы было много игроков, то было бы целесообразно объединить это значение с одним или несколькими промежуточными уровнями брокера. Например, если в игре существует 1 миллион игроков, вы можете объединить значения с 1000 брокерами, каждый из которых отвечает за отслеживание 1000 отдельных игроков. Затем достижение подписывается на этих брокеров, а не на всех игроков напрямую. Конечно, оптимальная иерархия и количество подписчиков зависит от конкретной реализации.
В случае с вашим примером боя игроки могут публиковать подробности своего последнего боя точно таким же образом. Достижение, которое контролирует прыжки в боях, подписалось бы на эту информацию и проверило количество прыжков. Поскольку никакого исторического государства не требуется, оно также не растет со временем. Опять же, нет необходимости изменять основной код; вам нужно только иметь доступ к некоторым значениям.
Обратите внимание, что большинство наград не обязательно должны быть мгновенными. Это дает вам некоторую свободу в управлении вашим трафиком. В предыдущем примере вы не можете обновлять опубликованное пройденное расстояние брокера до тех пор, пока игрок не пройдет в общей сложности еще одну милю или не пройдет день с момента последнего обновления (до тех пор, пока он не увеличится). Это действительно просто форма кеширования; точные параметры будут зависеть от вашей проблемы.
Вы даже можете сделать это, если у вас нет доступа к источнику, например, в эмуляторах видеоигр. Простой инструмент сканирования памяти может быть написан, чтобы найти отображаемый счет, например. Если у вас есть такая система достижений, вам просто нужно опрашивать эту ячейку памяти каждый кадр и определять, превышает ли их текущий "балл" их самый высокий балл. Крутая вещь в эмуляторах видеоигр состоит в том, что области памяти являются детерминированными (без операционной системы).
Есть два способа сделать это в обычных играх.
- Оффлайн игры: ничего сложнее, чем паб / саб - это огромное излишество. Вместо этого вы просто используете большую карту / словарь и ведете журнал с именем "events". Затем каждые X кадров или Y секунд (или, обычно: "каждый раз, когда что-то умирает, и 1x в конце уровня"), вы перебираете достижения и делаете быструю проверку. Когда дизайнеры хотят, чтобы новое событие было зарегистрировано, для программиста тривиально добавить строку кода для его записи.
NB: pub / sub плохо подходит для этого IME, потому что дизайнеры никогда не хотят "когда player.distance = 50". На самом деле они хотят, чтобы "когда расстояние игрока, воспринимаемое кем-то, смотрящим на экран, казалось, прошло через первую деревню, или, по крайней мере, на 4 ширины экрана вправо", то есть гораздо более размытое и абстрактное, чем простой счетчик.
На практике это означает, что логика идет в момент, когда происходит изменение (еще до того, как событие было опубликовано), что является плохим способом использования pub/sub. Есть некоторые игровые движки, которые облегчают выполнение "логики в точке получения" (часть "sub"), но они не являются большинством, IME.
- Онлайн-игры: практически идентичны, за исключением того, что вы храните "счетчики" (int, который идет вверх), и обычно также: "deltas" (циклические буферы того, что произошло, кадр за кадром), и: "события" (сложные вещи, которые происходили в игре это может быть жестко закодировано в один идентификатор плюс массив параметров фиксированного размера). Затем они предоставляются через, например, SNMP другим серверам для сбора данных при низких затратах процессора и асинхронно
т.е. почти так же, как 1 выше, за исключением того, что вы осторожны, чтобы сделать две вещи:
- Использование памяти фиксированного размера; и если "читающие" серверы на некоторое время отключаются, то достижения, выигранные за это время, необходимо будет повторно завоевать (хотя обычно вы можете попросить сотрудника службы поддержки вручную просмотреть основные системные журналы и выяснить, что достижение "вероятно" был выигран, и вручную награждаем его)
- Очень низкие накладные расходы; SNMP является хорошим стандартом для этого, и большинство знакомых мне команд в конечном итоге используют его
Если ваша игровая архитектура основана на событиях, то вы можете внедрить систему достижений, используя конечные автоматы.