Игровой баланс. Часть 3

Краткое содержание цикла про баланс:
— Введение и подготовка к работе
— Начало работы: константы и прогрессии
— Боевой баланс или расчет эффективности
— Модели и экономика

Расчет эффективности

Таким образом я называю, наверное, самую очевидную часть работы: боевой баланс, баланс между фракциями, стратегиями, юнитами и зданиями разных уровней и тому подобное.

Напоминаю, мы делаем мобильный баттлер.
Как убедиться, что вот эта карта 23-его уровня равна по силе другой карте той же ценности того же уровня?
Как контролировать, что любая «редкая карта» на любом уровне ровно в двое сильнее любой «обычной карты»?
В других жанрах похожие задачи: вот два строения в ситибилдере с похожей ценой, но разной функцией — как сделать их равными по «полезности»?

Универсальный ответ: сводите всю параметры к одному. Можете назвать его «эффективность», «полезность», «сила», как угодно.

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

Боевая эффективность

Сила юнита = HP * DMG.

Вот так просто, серьезно.
Даже если в игре два десятках параметров, все они сводятся сначала к этим двум, а потом и к одному.
Иначе говоря: ОТНОСИТЕЛЬНАЯ ЭФФЕКТИВНОСТЬ ЮНИТА =
HP [ 
СУММА УРОНА, КОТОРЫЙ Я ПРИМУ ] * DMG [ МОЕГО УРОНА ЗА ЕД.ВРЕМ.

Рассмотрим другие параметры.
Например, есть процентный шанс нанести двойной урон (CRIT).
Тогда DMG = DMG * ( 1 + CRIT% ). То есть, добавить 50%-ый шанс крита на языке баланса то же самое, что увеличить базовый урон на 50%. Все просто и логично.

Или, например, есть шанс избежать атаку врага (DODGE).
Тогда HP = HP / ( 1 — DODGE%). То есть, 50%-ый шанс увернуться равен увеличению здоровья вдвое: логично, т.к. уворот от половины атак позволит юниту вдвое дольше прожить в бою. Точно так же считаются эффекты типа PARRY и ABSORB.

Но если эффектов несколько, то надо смотреть, как они складываются. Например, уворот вместе с поглощением урона — поглощение срабатывает только тогда, когда не сработал уворот. Раз они действуют по-очереди — их нельзя складывать. В таком случае формула будет выглядеть так:
HP = HP / ( 1 — ( DODGE%+ ABSORB%*(1-DODGE%) )
То есть, ABSORB надо уменьшать на вероятность уворота: больше уворот — реже поглощение.

Дальше, по аналогии, можно рассчитывать не только параметры юнитов, но так же предметов, заклинаний, зданий и прочего.

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

Параметры из эффективности

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

Проще всего это делать с помощью коэффициентов к средним значениям: например, для «танка» нужно будет указать, что его здоровье в 1.5 раза выше среднего.

Теперь подробно: допустим, сила (PW) юнитов 1-ого уровня = 100.
Тогда средние значения HP и DMG = SQRT(100) = 10 (квадратный корень из эффективности).
Однако, ранее мы решили, что здоровье должно быть в 6 раз больше урона.
Пересчитываем: среднее HP = SQRT(100) * SQRT(6) = 24
Соответственно, среднее DMG = 24/6 = 4
Проверяем: 24 * 4 = 96 (не ровно 100, т.к. до этого я округлил, но в рамках баланса такие погрешности допустимы)

Теперь мы хотим сделать «танка».
Нам надо умножить средний HP на ранее выбранный множитель = 24 * 1.5 = 37
соответственно DMG = 4 * ( 1 / 1.5 ) = 4 * 0.7 = 3
Проверяем: 37 * 3 = 111 (Все получилось, хоть и с погрешностью округления).

В итоге наши расчеты будут выглядеть примерно так: t11 В этой таблице единственное вручную задаваемое число — коэффициент к HP.

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

Заполнение вручную

Параметры можно вписывать и вручную, а формулой только «проверять», чтобы вписанное не сильно отличалось от расчетного.

Как это может выглядеть: t10

Теперь все значения внесены вручную, а под каждым юнитом есть столбик с проверкой. В нем — относительная разница между полученным PW и расчетным, которая подсвечивается красным (conditional formating), если превышает 10%.

  • Плюсы вписывания: значения лучше смотрятся, их можно связать с эмоциями, например «Адская бомба с уроном 666″.
    Еще я люблю использовать четные цифры для «толстых» юнитов и нечетные для дамагеров.
    А эпические юниты хорошо смотрятся с круглыми числами.
  • Минусы вписывания: больше работы, больше мусора в таблицах и выше риск ошибки.

Aвтоматическое заполнение с коэффициентами или ручное с проверкой — выбор за вами.
Если ваши юниты и способности могут прокачиваться на десятки уровней — в эмоциональных числах нет никакого смысла, все-равно их почти не будет заметно.
Зато, если речь о каком-то уникальном контенте, который не меняется и не имеет сотню состояний — задумайтесь о ручном заполнении, с ним красивее.

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

На этом основы кончаются, а мы можем спокойно получить все параметры всех юнитов. Переходим к обещaнным нюансам.

Дополнительно

Как уже упоминал: автоматизация вносит погрешность.
Видя перед собой только цифры мы забываем про вещи, казалось бы, очевидные. Их лучше провоговорить заранее и учитывать при балансировке.

(Не)очевидные параметры

Да, все параметры сводятся к HP и DMG, это чистая математика.

Но в балансе всегда есть здоровая доля «магии» из-за невозможности предсказать и посчитать все возможные события и комбинации.
И не везде есть прямое математическое решение — иногда вам придется вносить изменения «на глаз» и проверять в прототипе.

Вот некоторые примеры.

Самый очевидный: лечение.
Легко догадаться, что для целителя DMG = силе исцеления. Однако, атакующий всегда найдет цель, а целитель может быть неэффективен, когда он один на поле или когда все здоровы. Плюс он не лечит выше максимального здоровья.
Поэтому, при сравнении целителя и дамагера с одинаковыми параметрами, расчетная эффективность целителя должна быть ниже.
Я обычно использую коэффициент 0.7-0.8 к DMG.

Другой пример: лучник атакует летающие цели, рыцарь — нет.
Лучник, очевидно, «эффективнее» и для правильного баланса ему надо заложить коэффициент к урону.
Но подбирать коэффициент придется «на глаз», опираясь на тестирование и некоторые соображения. Например:

  • Количество летунов в игре. Если летун, допустим, всего один — к-т должен быть минимален.
  • Эффективность самих летунов. Если все ленуты заведомо слабые и легко выносимые, а «лучников» в игре много — к-т так же не должен быть слишком высоким.

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

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

  • Во-1-х, далеко не всегда столкновение будет начинаться с максимального радиуса атака. В играх типа Clash Royale можно скидывать юнитов с ближней атакой прямо на юнитов с дальней — тогда весь эффект дальнего боя сводится к нулю.
    В каждой игре свои ограничения — считая по максимуму мы, скорее всего, завысим эффективность.
  • Во-2-х, мы не учитываем тактику комбинирования «жирных» юнитов спереди и дальнобойных сзади. В зависимости от игры эта тактика может быть выгодна по-разному, от «вообще не имеет смысла» (к-т минимальный), до «только так и нужно играть» (к-т максимальный). Определитесь, что нужно для геймплея — и подкрепите этот вариант коэффициентом.

Этот же пример можно отнести ко всем вопросам позиционирования, включая, например, преграждение пути, замедление, другие формы crowd-controll’a.

И в каждом случае есть логичное, но не полное математическое решение: например, для мага с «заморозкий» можно посчитать среднее число поражаемых целей, умножить на среднюю атаку и на его силу замедления — получится обоснованное число «урона, который цели не смогли нанести из-за эффекта замедления», и это число смело можно плюсовать к DMG мага.
Но в зависимости от механик и тактик игры — реальная эффективность может сильно отличатся от наших расчетов.
Так что, без тестирования и правок «на глаз» не обойтись.

Эффективность группы

Этот вопрос уже упоминался: если в игре есть битвы с разным количеством юнитов или юниты типа «отряд из N персонажей» — мы должны знать, как посчитать их эффективность с учетом количества.

Просто умножить «силу» на количество недостаточно — наше число будет отражать «силу» отряда, в котором одновременно сражается только один юнит.

На количество (N) следует умножить отдельно HP, отдельно DMG:
PW(N) = ( HP*N ) * ( DMG*N )
Иначе это можно записать HP*DMG*N², что кажется даже логичнее — но мы так делать не будем, и вот почему: эта запись отражает эффективность отряда, который имеет общее здоровье и постоянный урон, не меняющийся от гибели членов отряда.

В реальности такое встречается редко, поэтому DMG надо понизить на коэффициент, отражающий смертность. А это уже зависит от конкретных механик игры, например — распространенности AoE атак, возможности отряда атаковать на расстоянии и т.д.

Возьмем, навскидку, коэффициент 0.7 и тогда формула выглядит так:
PW(N) при N>1 = ( HP * N ) * ( DMG0.7N )

Но если вы хотите использовать одну формулу и для отрядов и для одиночных героев, то ее надо переписать:
PW(N) = ( HP*N ) * ( DMG + DMG * 0.7 * (N-1) )

Рейтинги вместо процентов

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

Начну с проблемы: допустим, мы делаем классический World of Warcraft и хотим, чтобы рыцарь-защитник в нормальной броне поглощал 40% урона.
Это правильная логика: она закрепляет за классом определенную роль на протяжении всей игры, что гораздо лучше, чем если бы в начале было 10%, а в конце — под 80%.

Но вот проблема: все параметры в MMO должны расти. Зачем нам ходить в рейды и валить боссов, если первая броня дает 40% и последняя — тоже 40%? Плюс, есть риск превысить 100%.

У проблемы есть решение: пусть броня 5-ого уровня дает 40% защиты только против врагов 5-ого уровня.
А против врагов 6-ого уровня та же броня даст, скажем, 36%. Против 7-ого всего 32% — и так далее. Таким образом мы сохраним роль классов и обеспечим потребность в постоянном росте.

Технически решение звучит так: процентный параметр делается зависимым от абсолютного значение параметра (рейтинга) и другого модификатора (например — уровня атакующего врага).
Модификатором может быть и уровень самого героя и любой другой параметр, например «пробитие брони» у атакующего.

Недостаток у такого метода ровно один: все это придется объяснять игроку. И вместо простых и удобных процентов, показывать, в довесок, непонятный «рейтинг брони».
К счастью, тот же World of WarCraft уже воспитал поколение привычных к этому игроков.

Теперь: как это делать.
Рассматриваем на том же примере: 40% защиты против врага того же уровня.

Сперва нам нужна прогрессия нормальных значений брони для этого класса. То есть: сколько «рейтинга брони» (ARMOR) должно быть у игрока на каждом уровне, чтобы его поглощение (ARMOR%) было = 40%.

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

Формула, которая превратит рейтинг в процент выглядит просто:
ARMOR% = ARMOR / ( ARMOR + PENETRATION )
Легко догадаться, что за счет деления числа на его сумму с другим положительным числом мы никогда не получим > 100%

Теперь разберемся с PENETRATION.
В самом простом сценарии — это значение из той же прогрессии, взятое по уровню врага.
Тогда, против равного врага мы будем иметь:
ARMOR / ( ARMOR + PENETRATION ) = 50% поглощения.
Нам, однако, требовалось 40%.
Для этого мы должны сделать еще одну прогрессию: пенетрации. И значения в ней должны быть в 1.5 раза выше, чем в предыдущей прогрессии.

Таким образом: у нас 10-ый уровень, для которого требуется, допустим, 300 брони. Нас бьет враг 10-ого же уровня, с пенетрацией 300*1.5=450.
Считаем:  300 / ( 300 + 450 ) = 40%
То, что надо.

Теперь, подбирая модификаторы мы можем расписать ожидаемые значения брони для всех классов.
Если нам не нравится, как падает или повышается % от разницы в уровнях — мы  можем добавить зависимость второго слагаемого от этой разницы.

И последнее: в нашей ММОRPG полученный урон будет расчитываться на сервере по той формуле, с которой сделаны прогрессии брони и пенетрации. Если для прогрессии вы использовали фибоначчи — вас, скорее всего, засунут в блендер и порвут на сотню маленьких геймдизайнеров.

________________

В следующем посте: модели и экономика. Он, скорее всего, выйдет с задержкой.