Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

An element with the same key already exists in the dictionary/The given key was not present in the d

Discussion in 'Scripting' started by Rekimo, May 25, 2018.

  1. Rekimo

    Rekimo

    Joined:
    May 25, 2018
    Posts:
    6
    Hello,
    I have problem with c# script in unity(2018).
    I don't know what is wrong .. maybe new version(Unity).
    Before update works fine .. and now .. not.

    Two errors:

    Code (CSharp):
    1. ArgumentException: An element with the same key already exists in the
    2.  
    3.     dictionary.
    4.     System.Collections.Generic.Dictionary`2[System.String,UnityEngine.Vector2[]].Add (System.String key, UnityEngine.Vector2[] value) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:404)
    5.     SpriteLoader.Awake () (at Assets/Scripts/SpriteLoader.cs:42)
    and this:

    Code (CSharp):
    1. KeyNotFoundException: The given key was not present in the dictionary.
    2.     System.Collections.Generic.Dictionary`2[System.String,UnityEngine.Vector2[]].get_Item (System.String key) (at /Users/builduser/buildslave/mono/build/mcs/class/corlib/System.Collections.Generic/Dictionary.cs:150)
    3.     SpriteLoader.GetTileUVs (.Tile tile) (at Assets/Scripts/SpriteLoader.cs:67)
    4.     MeshData.CreateSquare (Int32 x, Int32 y) (at Assets/Scripts/MeshData.cs:43)
    5.     MeshData..ctor (Int32 x, Int32 y, Int32 width, Int32 height) (at Assets/Scripts/MeshData.cs:21)
    6.     World.GenerateMesh (Int32 x, Int32 y, Int32 width, Int32 height) (at Assets/Scripts/World.cs:90)
    7.     World.SubdivideTilesArray (Int32 i1, Int32 i2) (at Assets/Scripts/World.cs:73)
    8.     World.Start () (at Assets/Scripts/World.cs:25)
    World:


    Code (CSharp):
    1. using UnityEngine;
    2.  
    3.     public class World : MonoBehaviour
    4.     {
    5.     public static World instance;
    6.  
    7.     public Material material;
    8.  
    9.     public int width;
    10.     public int height;
    11.  
    12.     public Tile[,] tiles;
    13.  
    14.     // Use this for initialization
    15.     void Awake()
    16.     {
    17.         instance = this;
    18.     }
    19.  
    20.     void Start()
    21.     {
    22.         CreateTiles();
    23.         SubdivideTilesArray();
    24.     }
    25.  
    26.     // Update is called once per frame
    27.     void Update()
    28.     {
    29.  
    30.     }
    31.  
    32.     void CreateTiles()
    33.     {
    34.         tiles = new Tile[width, height];
    35.  
    36.         for (int i = 0; i < width; i++)
    37.         {
    38.             for (int j = 0; j < height; j++)
    39.             {
    40.                 tiles[i, j] = new Tile(Tile.Type.Grass);
    41.             }
    42.         }
    43.     }
    44.  
    45.     void SubdivideTilesArray(int i1 = 0, int i2 = 0)
    46.     {
    47.         if (i1 > tiles.GetLength(0) && i2 > tiles.GetLength(1))
    48.             return;
    49.  
    50.         //Get size of segment
    51.         int sizeX, sizeY;
    52.  
    53.         if (tiles.GetLength(0) - i1 > 100)
    54.         {
    55.             sizeX = 100;
    56.         }
    57.         else
    58.         {
    59.             sizeX = tiles.GetLength(0) - i1;
    60.         }
    61.  
    62.         if (tiles.GetLength(1) - i2 > 100)
    63.         {
    64.             sizeY = 100;
    65.         }
    66.         else
    67.         {
    68.             sizeY = tiles.GetLength(1) - i2;
    69.         }
    70.  
    71.         GenerateMesh(i1, i2, sizeX, sizeY);
    72.  
    73.         if (tiles.GetLength(0) > i1 + 100)
    74.         {
    75.             SubdivideTilesArray(i1 + 100, i2);
    76.             return;
    77.         }
    78.  
    79.         if (tiles.GetLength(1) > i2 + 100)
    80.         {
    81.             SubdivideTilesArray(0, i2 + 100);
    82.             return;
    83.         }
    84.     }
    85.  
    86.     void GenerateMesh(int x, int y, int width, int height)
    87.     {
    88.         MeshData data = new MeshData(x, y, width, height);
    89.  
    90.         GameObject meshGO = new GameObject("Chunk_" + x + "_" + y);
    91.         meshGO.transform.SetParent(this.transform);
    92.  
    93.         MeshFilter filter = meshGO.AddComponent<MeshFilter>();
    94.         MeshRenderer render = meshGO.AddComponent<MeshRenderer>();
    95.         render.material = material;
    96.  
    97.         Mesh mesh = filter.mesh;
    98.  
    99.         mesh.vertices = data.vertices.ToArray();
    100.         mesh.triangles = data.triangles.ToArray();
    101.         mesh.uv = data.UVs.ToArray();
    102.     }
    103.  
    104.     public Tile GetTileAt(int x, int y)
    105.     {
    106.         if (x < 0 || x >= width || y < 0 || y >= height)
    107.         {
    108.             return null;
    109.         }
    110.         return tiles[x, y];
    111.     }
    112.     }
    MeshData:


    Code (CSharp):
    1. using System.Collections.Generic;
    2.     using UnityEngine;
    3.  
    4.     public class MeshData
    5.     {
    6.         public List<Vector3> vertices;
    7.         public List<Vector2> UVs;
    8.         public List<int> triangles;
    9.  
    10.         public MeshData(int x, int y, int width, int height)
    11.         {
    12.             vertices = new List<Vector3>();
    13.             UVs = new List<Vector2>();
    14.             triangles = new List<int>();
    15.  
    16.             for (int i = x; i < width + x; i++)
    17.             {
    18.                 for (int j = y; j < height + y; j++)
    19.                 {
    20.                     CreateSquare(i, j);
    21.                 }
    22.             }
    23.         }
    24.  
    25.         void CreateSquare(int x, int y)
    26.         {
    27.             Tile tile = World.instance.GetTileAt(x, y);
    28.  
    29.             vertices.Add(new Vector3(x + 0, y + 0));
    30.             vertices.Add(new Vector3(x + 1, y + 0));
    31.             vertices.Add(new Vector3(x + 0, y + 1));
    32.             vertices.Add(new Vector3(x + 1, y + 1));
    33.  
    34.             triangles.Add(vertices.Count - 1);
    35.             triangles.Add(vertices.Count - 3);
    36.             triangles.Add(vertices.Count - 4);
    37.  
    38.             triangles.Add(vertices.Count - 2);
    39.             triangles.Add(vertices.Count - 1);
    40.             triangles.Add(vertices.Count - 4);
    41.  
    42.             UVs.AddRange(SpriteLoader.instance.GetTileUVs(tile));
    43.         }
    44.     }
    SpriteLoader:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class SpriteLoader : MonoBehaviour
    6. {
    7.     public static SpriteLoader instance;
    8.  
    9.     Dictionary<string, Vector2[]> tileUVMap;
    10.  
    11.     // Use this for initialization
    12.     void Awake()
    13.     {
    14.         instance = this;
    15.  
    16.         tileUVMap = new Dictionary<string, Vector2[]>();
    17.  
    18.         Sprite[] sprites = Resources.LoadAll<Sprite>("");
    19.  
    20.         float imageWidth = 0f;
    21.         float imageHeight = 0f;
    22.  
    23.         foreach (Sprite s in sprites)
    24.         {
    25.             if (s.rect.x + s.rect.width > imageWidth)
    26.                 imageWidth = s.rect.x + s.rect.width;
    27.  
    28.             if (s.rect.y + s.rect.height > imageHeight)
    29.                 imageHeight = s.rect.y + s.rect.height;
    30.         }
    31.  
    32.         foreach (Sprite s in sprites)
    33.         {
    34.  
    35.             Vector2[] uvs = new Vector2[4];
    36.  
    37.             uvs[0] = new Vector2(s.rect.x / imageWidth, s.rect.y / imageHeight);
    38.             uvs[1] = new Vector2((s.rect.x + s.rect.width) / imageWidth, s.rect.y / imageHeight);
    39.             uvs[2] = new Vector2(s.rect.x / imageWidth, (s.rect.y + s.rect.height) / imageHeight);
    40.             uvs[3] = new Vector2((s.rect.x + s.rect.width) / imageWidth, (s.rect.y + s.rect.height) / imageHeight);
    41.  
    42.             tileUVMap.Add(s.name, uvs);
    43.         }
    44.  
    45.     }
    46.  
    47.     // Update is called once per frame
    48.     void Update()
    49.     {
    50.  
    51.     }
    52.  
    53.     public Vector2[] GetTileUVs(Tile tile)
    54.     {
    55.  
    56.         string key = tile.type.ToString();
    57.  
    58.         if (tileUVMap.ContainsKey(key) == true)
    59.         {
    60.  
    61.             return tileUVMap[key];
    62.         }
    63.         else
    64.         {
    65.  
    66.             Debug.LogError("There is no UV map for tile type: " + key);
    67.             return tileUVMap["Void"];
    68.         }
    69.     }
    70. }
    71.  
    This only didn't works fine on this version(Unity)
    Code is for generate map in 2d.
     
  2. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    These are key duplicates and key not found exception. You can check for a key in a dictionary,
    https://msdn.microsoft.com/en-us/library/windows/apps/kw5aaea4(v=vs.85).aspx/css

    This should help you debug the problem you are having. Possibly also run only the sprite loader and debug it first. If it already has the key, you could be loading the script twice or something.

    I know some programs that use a static instance like that, check if it already exists and then destroys the copy. I've seen it done on singletons to avoid duplication.
     
    Last edited: May 26, 2018
  3. Rekimo

    Rekimo

    Joined:
    May 25, 2018
    Posts:
    6
    I added "try" to tileUVMap.Add and i got this: http://prntscr.com/jmtjkc
     
  4. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    One thing you could try is to check for duplicates. I don't use singletons much but generally they do:
    Code (csharp):
    1.  
    2. if(instance == null)
    3. instance = this;
    4. else{
    5. Destroy(this.gameObject);
    6. }
    7.  
    Since the names look authentic, you can only assume that a duplicate has already loaded them.
     
    Last edited: May 26, 2018
  5. Rekimo

    Rekimo

    Joined:
    May 25, 2018
    Posts:
    6
    I added this into World and SpriteLoader.
    Still the same: http://prntscr.com/jmzxpf
    And nothing has been "destroyed".
     
  6. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Try getting a count of the dictionary before it gets loaded in a debug, before the second for/each. Then get a count when it's finished.

    The other possibility is there are doubles of sprites that are getting loaded, so you might want to check that also and find out how many got loaded.
     
    Last edited: May 26, 2018
  7. Rekimo

    Rekimo

    Joined:
    May 25, 2018
    Posts:
    6
    Count:
    Before for/each = 0
    After for/each = 23

    ... I don't know why this: Sprite[] sprites = Resources.LoadAll<Sprite>("");
    load btn and etc
    .. i added new folder for sprites and added path... and now works fine
     
  8. fire7side

    fire7side

    Joined:
    Oct 15, 2012
    Posts:
    1,819
    Glad you got it working.