Это вторая часть туториала по характеристикам персонажа. Смотрите часть 1 здесь:
Есть также видеоверсия этого урока, если вы предпочитаете это:
Сейчас наши процентные модификаторы складываются мультипликативно друг с другом, то есть, если мы добавим два 100% модификатора к статистике, мы получим не 200%, а 400%. Потому что первое удвоит исходное значение (от 100% до 200%), а второе снова удвоит его (от 200% до 400%).
Но что, если мы хотим, чтобы определенные модификаторы складывались аддитивно? Это означает, что предыдущий пример приведет к бонусу 200% вместо 400%.
Давайте добавим третий тип модификатора, изменив наш StatModType
enum
на это:
Не забудьте изменить Percent
на PercentMult
в методе CalculateFinalValue()
(внутри класса CharacterStat
). Или просто используйте функции переименования Visual Studio, чтобы сделать это за вас ^^.
Внутри метода CalculateFinalValue()
нам нужно добавить пару вещей для работы с новым типом модификатора. Теперь это должно выглядеть так:
На этот раз расчет становится довольно странным. По сути, каждый раз, когда мы сталкиваемся с модификатором PercentAdd
, мы начинаем добавлять его вместе со всеми модификаторами того же типа, пока не встретим модификатор другого типа или не дойдем до конца списка. В этот момент мы берем сумму всех модификаторов PercentAdd
и умножаем ее на finalValue
, точно так же, как мы делаем с модификаторами PercentMult
.
Для следующего бита давайте добавим переменную Source
в наш класс StatModifier
. Таким образом, позже, когда в нашей игре появятся вещи, добавляющие модификаторы (например, предметы и заклинания), мы сможем сказать, откуда взялись те или иные модификаторы.
Это может быть полезно как для отладки, так и для предоставления игрокам дополнительной информации, позволяя им точно видеть, что дает каждый модификатор.
Класс StatModifier
должен выглядеть так:
Допустим, мы экипировали предмет, который дает как фиксированный +10, так и +10% бонус к Силе. Как система работает в настоящее время, мы должны сделать что-то вроде этого:
Но теперь, когда у наших модификаторов есть Source
, мы можем сделать кое-что полезное в CharacterStat
— мы можем удалить сразу все модификаторы, которые были применены определенным Source
. Добавим для этого метод:
Почему цикл
for
работает в обратном порядке?
Чтобы объяснить это, давайте посмотрим, что происходит, когда мы удаляем первый объект из списка по сравнению с когда мы удаляем последний объект:
Давайте представим, что у нас есть список с 10 объектами, когда мы удаляем первый, остальные 9 объектов будут смещены вверх. Это происходит потому, что индекс 0 теперь пуст, поэтому объект с индексом 1 переместится в индекс 0, объект с индексом 2 переместится в индекс 1. сильный> и так далее. Как вы понимаете, это довольно неэффективно.
Однако, если мы удалим последний объект, то ничего смещать не придется. Мы просто удаляемобъект с индексом 9, а все остальное остается прежним.
Вот почему мы делаем удаление в обратном порядке. Даже если объекты, которые нам нужно удалить, находятся в середине списка (где сдвиги неизбежны), все же рекомендуется пройтись по списку в обратном порядке (если только ваш конкретный вариант использования не требует иного). Каждый раз, когда удаляется более одного объекта, выполнение этого действия от последнего к первому всегда приводит к меньшему количеству смен.
И теперь мы можем добавлять и удалять модификаторы нашего (гипотетического) предмета следующим образом:
Поскольку мы говорим об удалении модификаторов, давайте также «поправим» наш оригинальный метод RemoveModifier()
. Нам действительно не нужно устанавливать isDirty
каждый раз, просто когда что-то действительно удаляется.
Мы также говорили о том, чтобы позволить игрокам видеть модификаторы, но список statModifiers
является закрытым. Мы не хотим это менять, потому что единственный способ безопасно изменить это, безусловно, через класс CharacterStat
. К счастью, в C# есть очень полезный тип данных для таких ситуаций: ReadOnlyCollection
.
Внесите следующие изменения в CharacterStat
:
ReadOnlyCollection
хранит ссылку на исходный List
и запрещает его изменение. Однако, если вы измените исходное statModifers
(строчная буква «s»), то StatModifiers
(верхняя буква «S») также изменится.
Чтобы закончить часть 2, я хотел бы добавить еще две вещи. Мы оставили BaseValue
общедоступным, но если мы его изменим, это не приведет к пересчету свойства Value
. Давайте это исправим.
Другое дело в StatModType
enum
. Давайте переопределим «индексы» значений enum
по умолчанию, например:
Причина для этого проста — если кто-то хочет добавить пользовательское значение Order
, чтобы некоторые модификаторы располагались посередине модификаторов по умолчанию, это обеспечивает гораздо большую гибкость.
Если мы хотим добавить модификатор Flat
, который применяется между PercentAdd
и PercentMult
, мы можем просто назначить Order
где-нибудь между 201 и 299.
Прежде чем мы внесем это изменение, нам нужно будет присвоить пользовательские значения Order
всем PercentAdd
и PercentMult
тоже модификаторы.
И это все для части 2. Не стесняйтесь оставлять комментарии, если у вас есть какие-либо вопросы, предложения или отзывы.
Я надеюсь, что это было полезно, и пока до свидания!