C# Конверсия индексов Jagged массива содержащего другой Jagged массив. Tilemap

178
13 августа 2018, 08:40

Имеется объект Cell который необходимо достать из массива Maps[][] методом World.GetCell(uint x, uint y). Maps[][] в свою очередь содержит так же джаггед массивы. То есть метод должен позволять обращать к массиву как к одному целому, а не состоящему из множества. Боже упаси делать, что то вроде List<List<>> и т.д. Вопрос сложный, если что спрашиваете.

Пример как использовать данный метод для нахождения позиции тайла в пикселях:

Vector2(World.GetCell(uint x, uint y).X * размерТайла, 
         World.GetCell(uint x, uint y).Y * размерТайла,)

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

Комментированный код для примера:

public static class Config
{
    public static byte MapSize = 64;
    public static ushort WorldSize = 128;
}
public enum CellType : uint
{
    SomeTypeOne,
    SomeTypeTwo
}
public struct Cell
{
    //public uint X; //Легкий вариант с сохраняемыми индексами, но жрет 
    //память ясное дело
    //public uint Y;
    public CellType CellType;
    public Cell(CellType cellType)
    {
        CellType = cellType;
    }
}
public struct Map
{
    public uint Id;
    //public uint X;
    //public uint Y;
    public Cell[][] Cells;
    public Map(uint id)
    {
        Id = id; 
        //Запихиваем прямо в конструкторе
        Cells = new Cell[Config.MapSize][];
        for (var i = 0; i < Config.MapSize; i++)
            Cells[i] = new Cell[Config.MapSize];
    }
}
public class World
{
    public Map[][] Maps = new Map[Config.WorldSize][];
    //public List<Map>; //более приемлемый вариант
    public void GetCell(uint x, uint y) =>
        throw new NotImplementedException(); //Вот сюда засунуть метод
    public World()
    {
        for (var i = 0; i < Config.WorldSize; i++)
            Maps[i] = new Map[Config.WorldSize];
    }
}

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

for(var i = 0; i < Config.WorldSize; i++)
{
    for (var j = 0; j < Config.WorldSize; j++)
    {
        for (var k = 0; k < Config.MapSize; k++)
        {
            for (var g = 0; g < Config.MapSize; g++)
            {
                var position = new Vector2(k * tileSize + i * tileSize * Config.MapSize,
                    g * tileSize + j * tileSize * Config.MapSize);
            }
        }
    }
}

///К вопросу не относиться

Кстати объект World будет весить около 2 гигов в памяти с данным кодом(Хотя со сжатием сохраняется по частям вполне норм через ZeroFormatter). Да, да знаю что грузить это надо динамически, а не все и сразу.

Answer 1

Поправьте если не правильно понял вашу идею.

  • Config.WorldSize - количество элементов Map в объекте World по вертикали и горизонтали.
  • Config.MapSize - количество элементов Cell в объекте Map по вертикали и горизонтали.

Тогда для нам потребуется два перехода: от общемировых координат к координатам Map внутри World и последующий переход к координатам Cell внутри Map.

public Cell GetCell(uint x, uint y)
{
    //координаты Map внутри World 
    uint xMap = x / Config.MapSize;
    uint yMap = y / Config.MapSize;
    //координаты Cell внутри Map
    uint xCell = x % Config.MapSize;
    uint yCell = y % Config.MapSize;
    //ну и отдаем найденную ячейку
    return Maps[xMap][yMap].Cells[xCell][yCell];
}

О том, почему это работает:

Рассмотрим следующую картинку

|0|1|2|3|4|5|6|7|8| //сквозная нумерация (мировые координаты)
|--0--|--1--|--2--| //нумерация регионов (Map в вашем случае)
|0|1|2|0|1|2|0|1|2| //нумерация внутри региона

Теперь возьмем для примера мировую координату 4 и посмотрим как из нее получить все остальное. Известна длина региона - 3. Следовательно если мы разделим нашу мировую координату на длину региона, то мы получим сколько целых регионов уместится до нашей координаты, а так как нумерация регионов начинается с 0, то полученное число будет номером региона, в который попала данная координата.

|0|1|2|3|4|5|6|7|8|
         ^          4 / 3 = 1
|--0--|--1--|--2--|

Осталось получить смещение внутри региона. Зная длину региона, мы можем использовать деление с остатком. Остаток всегда меньше делителя, следовательно может принимать любые целые значения от 0 до N-1, где N - длина региона. Как не сложно заметить - эти значения совпадают с номерами ячеек внутри региона.

|0|1|2|3|4|5|6|7|8|
         ^          4 % 3 = 1
|0|1|2|0|1|2|0|1|2|

На всякий случай: все использованные арифметические операции строго целочисленные.

И еще одна оговорка, такое простое решение подходит только для случая строго прямоугольных областей. Если же Map будет содержать строки разной длины, а Jagged array это позволяет (для этого он и был задуман), то простым решением уже не обойтись, хотя при таком варианте и мировые координаты использовать не получится.

READ ALSO
Подключиться к IP Камере

Подключиться к IP Камере

Есть ASP net mvc сайт, необходимо реализовать подключение к IP КамереВ представлении набросал поля для IP адреса/Порта/Логина/Пароля

170
Как правильно разделить текст на части?

Как правильно разделить текст на части?

В тексте (вакансии) есть три основных ключа : Требования, Условия, Обязанности

195
Интеграция оплаты на сайт

Интеграция оплаты на сайт

Пытался установить на сайт оплату через Paysera, но так и не могу додуматься как связать html страничку с php файлом, который предоставляется в оф документации...

181
Генерирующийся PHP файл

Генерирующийся PHP файл

Хотел задать несколько вопросов:

223