-1

I have a grid in my game that I store in a Dict Dictionary<Coord, Cell> cells = new Dictionary<Coord, Cell>(); where Coord is:

public Coord(int x, int z)
{
    this.x = x;
    this.z = z;
}

And Cell simply contains some int and string variables.

To get a specific cell I use:

public Cell GetCell(Coord coord)
{
    if (IsCoordWithinBorder(coord))
        return cells[coord];

    return null;
}

Where IsCoordWithinBorder looks like:

public bool IsCoordWithinBorder(Coord coord)
{
    return coord.x >= 0 && coord.z >= 0 && coord.x < size && coord.z < size;
}

This seems to generate a ton of garbage, and I have no clue why.

One instance it creates a lot of garbage is when I try to find all surrounding cells:

public List<Cell> GetSurroundingCells(Coord coord, int distance)
{
    List<Cell> matches = new List<Cell>();

    for (int x = coord.x - distance; x <= coord.x + distance; x++)
    {
        for (int z = coord.z - distance; z <= coord.z + distance; z++)
        {
            Cell cell = GetCell(new Coord(x, z));

            if (cell != null)
                matches.Add(GetCell(new Coord(x, z)));
        }
    }

    return matches;
}

From what I can gather from the Unity profiler, it all points to my GetCell()-method. Am I doing something wrong here?

EDIT:

for (int x = 0; x < size; x++)
    {
        cells[x] = new Dictionary<int, Cell>();
        for (int z = 0; z < size; z++)
        {
            cells[x][z] = new Cell();
        }
    }
Majs
  • 607
  • 2
  • 7
  • 20
  • Not sure how I can add more details I literally posted all the code I have? Weird downvote. – Majs Jul 28 '20 at 10:10
  • Is `Coord` a `class` or a `struct`? You only showed the constructor ;) And yes it is probably because you create a new `Coord` al the time .. the fact that the profiler points to `GetCell` is also influenced by your method simply getting called a lot of times (nested for loops) – derHugo Jul 28 '20 at 10:13
  • @derHugo it is a class! Any advice on how I could do this without creating a new coord? – Majs Jul 28 '20 at 10:14
  • There was just recently a similar question with reference types as key in a dictionary: https://stackoverflow.com/questions/63129018/c-sharp-check-if-dictionary-contains-key-which-is-a-reference-type – SomeBody Jul 28 '20 at 10:39

2 Answers2

1

The issue here is most probably that you create a lot of instances of Coord.

I would probably rather use something like

Dictionary<int, Dictionary<int, Cell>> cells;

You would fill it via

cells = new Dictionary<int, Dictionary<int, Cell>>();
for (int x = 0; x < size; x++)         
{         
    // In your use-case here this is basically equivalent to
    //cells.Add(x, new Dictionary<int, Cell>());
    cells[x] = new Dictionary<int, Cell>();

    for (int z = 0; z < size; z++)             
    {    
        cells[x][z] = new Cell();             
    }         
}

and then do

public bool IsCoordWithinBorder(int x, int z)
{
    return x >= 0 && z >= 0 && x < size && z < size;
}

public Cell GetCell(int x, int z)
{
    if (IsCoordWithinBorder(x, z))
        return cells[x][z];

    return null;
}

public List<Cell> GetSurroundingCells(Coord coord, int distance)
{
    List<Cell> matches = new List<Cell>();

    for (int x = coord.x - distance; x <= coord.x + distance; x++)
    {
        for (int z = coord.z - distance; z <= coord.z + distance; z++)
        {
            Cell cell = GetCell(x, z);

            if (cell != null)
                matches.Add(GetCell(x, z));
        }
    }

    return matches;
}

Or if the indices are continues anyway maybe rather

Cell[,] cells;

You would fill it via

cells = new Cell[size, size];
for (int x = 0; x < size; x++)         
{             
    for (int z = 0; z < size; z++)             
    {                 
        cells[x, z] = new Cell();      
    }         
}

and then

public bool IsCoordWithinBorder(int x, int z)
{
    return x >= 0 && z >= 0 && x < size && z < size;
}

public Cell GetCell(int x, int z)
{
    if (IsCoordWithinBorder(x, z))
        return cells[x, z];

    return null;
}

public List<Cell> GetSurroundingCells(Coord coord, int distance)
{
    List<Cell> matches = new List<Cell>();

    for (int x = coord.x - distance; x <= coord.x + distance; x++)
    {
        for (int z = coord.z - distance; z <= coord.z + distance; z++)
        {
            Cell cell = GetCell(x, z);

            if (cell != null)
                matches.Add(GetCell(x, z));
        }
    }

    return matches;
}
derHugo
  • 83,094
  • 9
  • 75
  • 115
  • Cool, would I then create it like so: `for (int x = 0; x < size; x++) { for (int z = 0; z < size; z++) { infoCells.Add(x, new Dictionary()); infoCells[x].Add(z, new Cell()); } }` – Majs Jul 28 '20 at 10:31
  • @Majs exactly, Just updated and added the initialization for both solutions – derHugo Jul 28 '20 at 10:41
  • are you sure the Dict one should work? I get "The given key was not present in the dictionary." which makes sense since I did not Add it, Im just trying to set it. – Majs Jul 28 '20 at 10:46
  • Usually afaik the `dict[index] = ...` would either add or update the key .. but if you want to be sure you can use `Add` ofcourse – derHugo Jul 28 '20 at 10:49
  • seems neither solution works. I made an edit that explains. – Majs Jul 28 '20 at 10:56
  • see [`Difference of Dictionary.Add vs Dictionary[key]=value`](https://stackoverflow.com/questions/11557418/difference-of-dictionary-add-vs-dictionarykey-value) ;) – derHugo Jul 28 '20 at 10:56
  • Oh now I understand my bad sorry ... updated the way for a Dictionary! The `cells[x] = ..` only **once** since otherwise indeed it would make no sense or even erase the data from the z-loop iteration before ;) .. typing on smartphone so sometimes I oversee these things ^^ – derHugo Jul 28 '20 at 10:58
  • @derHuga you are right, my implementation was wrong – Majs Jul 28 '20 at 10:58
0

Unless you have redefined comparison for the Coord type, your dictionary should search for the exact same object, not merely a Coord object with the same x and z. See documentation for Object.Equals.

Abstraction
  • 1,108
  • 11
  • 25