C# Лямбда: манипулировать одним элементом в списке <T> - PullRequest
0 голосов
/ 05 августа 2020

Чем я занимаюсь

Я разрабатываю несколько систем-прототипов (инвентарь, оборудование, ...) для моей 2D-ролевой игры Unity. Здесь я столкнулся с проблемой List<Stat> stats, который держит игрок.

Что я пытаюсь сделать

На случай, если игрок поднимет предмет , он оснащается напрямую (пока). Предмет может содержать List<StatModifier> modifiers, который добавляется к PlayerStats. Каждый раз, когда элемент оснащается, запускается следующий делегат, который является частью класса EquipmentSystem (Singleton).

public delegate void OnEquipmentChanged(EquipableItem newItem, EquipableItem oldItem);
public OnEquipmentChanged onEquipmentChanged;

Класс PlayerStats подписывается на этот делегат в момент его создания.

// Start is called before the first frame update
void Start()
{
    List<StatModifier> empty = new List<StatModifier>();

    // Initialize Stats
    health = new Stat(100, empty, StatType.HP);
    mana = new Stat(200, empty, StatType.MANA);

    // Add stats to list
    stats = new List<Stat>();
    stats.Add(health);
    stats.Add(mana);

    // Subscribe new Function
    EquipmentSystem.instance.onEquipmentChanged += OnEquipmentChanged; 
}

Метод OnEquipmentChanged() затем пересчитывает статистику игрока, удаляя StatModifier из старого элемента и добавляя StatModifier из нового элемента. Эта статистика хранится в private List<Stat> stats в классе PlayerStats.

В чем моя проблема

Метод OnEquipmentChanged() вызывается правильно, но он делает работать не так, как задумано. StatModifier элемента следует добавлять только в том случае, если StatType совпадает с StatType в Stat. Таким образом, HP следует добавлять только к HP, Mana только к Mana и так далее. StatType - это publi c enum btw. Но в настоящее время функция добавляет все StatModifier ко всем Stat, имеющимся у игрока. Вот функция:

void OnEquipmentChanged(EquipableItem newItem, EquipableItem oldItem)
{
    if (oldItem != null) { //remove modifiers }
    if (newItem != null)
    {
        // add modifiers of new item if new item exists
        foreach (StatModifier item_sm in newItem.GetStatModifiers())
        {                
            int index = stats.FindIndex(stat => stat.GetStatType() == item_sm.GetStatType());

            Debug.Log("Found stat " + stats[index].GetStatType());

            stats[index].AddModifier(item_sm);
            Debug.Log("Added " + item_sm.GetModifierValue() + " " + (StatType)item_sm.GetStatType() + " to " + stats[index].GetStatType());
        }
    }
}

Установка точки останова показывает, что после первой итерации StatModifier уже был добавлен к обоим Stat s. Почему?

EDIT 1 : Вот (очень простой) код, который используется для добавления StatModifier к любому Stat. Каждый Stat имеет свой личный список StatModifier.

public void AddModifier(StatModifier modifier)
{
    if (modifier != null)
    {
        modifiers.Add(modifier);
    }
}

Спасибо!

Ответы [ 2 ]

2 голосов
/ 05 августа 2020

Ваша проблема в этой строке:

stats[index].AddModifier(item_sm);

Какой бы ни была у вас реализация AddModifier, она делает неправильные вещи.

Хотя весь код излишне сложен и хрупок , зачем вам список одинаковых объектов, представляющих разные характеристики, которые вам нужно найти с помощью FindIndex? Вот для чего нужны словари. Фактически, для этого нужны отдельные переменные, и это сделало бы ваш код намного более эффективным. элемент, который вы заменяете, а затем добавляете новый элемент. Подумайте о порядке действий здесь: любой удаленный стат flat life будет удален раньше, чем будет добавлен показатель life% другого снаряжения. Правильный способ - вести список каждого модификатора, независимо от его источника, и при необходимости go по всему этому суммировать правильные вещи в правильном порядке, а затем использовать статистику.

0 голосов
/ 05 августа 2020

Я бы использовал другой подход. Я не думаю, что лямбда - это путь к go. Это псевдокод. У меня нет всего кода вашего класса, поэтому я не могу написать код именно для вас, но я бы сделал что-то вроде этого.

foreach (StatModifier item_sm in newItem.GetStatModifiers())
{           
     foreach (Stat stat in stats) {
          if (item_sm.GetStatType() == stat.statType) {
          // remove previous stat from a previous equipped item
          stat.AddModifier(item_sm);
          }
     }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...