Ошибка с массивом в C# (элементы не всегда установлены)

Я использую неровный массив для хранения сегментов карты (кластеров) в игре, которую я делаю. Положение в массиве соответствует положению кластера на карте. Кроме того, если во внутреннем массиве (зазубренной части) больше нет кластеров, загруженных в него (кластеры удаляются из массива после неиспользованного тайм-аута), то этот элемент внешнего массива возвращается в ноль, чтобы сохранить использование памяти карты вниз.

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

public Cluster getCluster(int xIndex, int yIndex)
{
    lock (xAxis)
    {
        loadCluster(xIndex, yIndex);
        return xAxis[xIndex][yIndex];
    }
}

public void loadCluster(int xIndex, int yIndex)
{
    lock (xAxis)
    {
        if (xAxis[xIndex] == null)
            xAxis[xIndex] = new Cluster[(int)worldSize.Y];
        if (xAxis[xIndex][yIndex] == null)
            xAxis[xIndex][yIndex] = new Cluster(this, new Vector2(xIndex * 256, yIndex * 256), worldLoader.loadClusterData(xIndex, yIndex));
    }
}

loadCluster(int, int) метод должен обеспечить загрузку кластера в массив до того, как getCluster(int, int) метод извлекает его и почти все время, но иногда loadCluster(int, int) как-то не удается добавить кластер.

Похоже, что это не происходит с каким-либо конкретным кластером, но всегда происходит, когда внутренний массив не был добавлен (однако, большую часть времени он создает внутренние массивы без проблем вообще). Кроме того, когда Visual Studio перехватывает последующее исключение нулевого указателя, отступая и повторно вызывая loadCluster(int, int) всегда (по крайней мере пока) работает как обычно. Добавление дополнительных звонков loadCluster(int, int) в getCluster(int, int) Метод также значительно снижает частоту появления этой ошибки.

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

РЕДАКТИРОВАТЬ: другой код, который редактирует xAxis[][]

public override void Update(GameTime gameTime)
{
    for (int x = 0; x < worldSize.X; x++)
    {
        if (xAxis[x] == null) continue;
        int loaded = 0;
        for (int y = 0; y < worldSize.Y; y++)
        {
            if (xAxis[x][y] == null)
            {
                continue;
            }
            xAxis[x][y].Update(gameTime);

            if (xAxis[x][y].clusterLoaded)
            {
                loaded++;
            }
            else if (xAxis[x][y].clusterTimer == 0)
            {
                xAxis[x][y] = null;
            }
        }

        if(loaded == 0) xAxis[x] = null;
    }
}

Cluster.clusterLoaded является логическим значением, показывающим, используется ли кластер в данный момент.Cluster.clusterTimer это int, который отсчитывает один раз clusterLoaded становится ложным Сбрасывается, если его максимальное значение, если clusterLoaded снова становится правдой. Уменьшается на 1 каждый раз Cluster.Update(GameTime) работает в то время как clusterLoaded ложноloaded используется для подсчета количества кластеров в текущем внутреннем массиве.

1 ответ

Решение

Первое, что нужно изменить, это изменить метод loadCluster так, чтобы он возвращал значение xAxis[xIndex][yIndex] прямо из него. Тогда не нужно будет блокировать метод getCluster. Что касается других разделов кода - из описания это, кажется, проблема многопоточности. Хотя вы заблокировали переменную xAxis, я не знаю, что еще вы делаете где-то еще. Еще один момент - массивы в языке действительно являются основной функциональностью, поэтому действительно неожиданно иметь ошибку там (я имею в виду Microsoft).

Другие вопросы по тегам