Search Unity

Trouble setting up List using Dictionary (C#)

Discussion in 'Scripting' started by Freecell, Aug 17, 2017.

  1. Freecell

    Freecell

    Joined:
    Aug 1, 2017
    Posts:
    4
    I'm making a tile-based game. My intention is to create map layouts in Photoshop, where each pixel represents a tile. The color of each pixel in the map image determines which tile goes in each spot in the game. I'm currently trying to write the code to import the map images and use them to populate the game board.
    In the code below, "MapColor" represents the pixel index of its tile type - a solid red pixel in the map png will correspond with a wall tile on the game board, for example.

    Here's the code snippet I'm having trouble with:
    Code (csharp):
    1.  
    2.  
    3. List<Tile>TileTypes;
    4.  
    5. protected class Tile
    6.     {
    7.         public static Dictionary<string, int> typeDic = new Dictionary<string, int>()
    8.         {
    9.             {"Grass",  0 },
    10.             {"Sand", 1 },
    11.             {"Mountain", 2 },
    12.             {"Water", 3 },
    13.             {"Wall", 4 }
    14.         };
    15.         public bool Is_Walkable { get; set; }
    16.         public bool Is_Swimmable { get; set; }
    17.         public bool Is_Flyable { get; set; }
    18.         public Color32 MapColor { get; set; }
    19.     }
    20.  
    21.     void InitTiles()
    22.     {
    23.         //Create blank tile types up to the number of available tile types.
    24.         Tile blank = new Tile();
    25.         for(int i = 0; i<tileCount;i++)
    26.         {
    27.             TileTypes.Add(blank);
    28.         }
    29.         //Populate tile variables
    30.         TileTypes[Tile.typeDic["Water"]].Is_Walkable = false;
    31.         TileTypes[Tile.typeDic["Water"]].Is_Swimmable = true;
    32.         TileTypes[Tile.typeDic["Water"]].Is_Flyable = true;
    33.         TileTypes[Tile.typeDic["Water"]].MapColor = new Color32(0,0,255,255);
    34.  
    35.         TileTypes[Tile.typeDic["Sand"]].Is_Walkable = true;
    36.         TileTypes[Tile.typeDic["Sand"]].Is_Swimmable = false;
    37.         TileTypes[Tile.typeDic["Sand"]].Is_Flyable = true;
    38.         TileTypes[Tile.typeDic["Sand"]].MapColor = new Color32(255, 255, 0, 255);
    39.  
    40.         TileTypes[Tile.typeDic["Grass"]].Is_Walkable = true;
    41.         TileTypes[Tile.typeDic["Grass"]].Is_Swimmable = false;
    42.         TileTypes[Tile.typeDic["Grass"]].Is_Flyable = true;
    43.         TileTypes[Tile.typeDic["Grass"]].MapColor = new Color32(0, 255, 0, 255);
    44.  
    45.         TileTypes[Tile.typeDic["Mountain"]].Is_Walkable = true;
    46.         TileTypes[Tile.typeDic["Mountain"]].Is_Swimmable = false;
    47.         TileTypes[Tile.typeDic["Mountain"]].Is_Flyable = true;
    48.         TileTypes[Tile.typeDic["Mountain"]].MapColor = new Color32(255, 255, 255, 255);
    49.  
    50.         TileTypes[Tile.typeDic["Wall"]].Is_Walkable = false;
    51.         TileTypes[Tile.typeDic["Wall"]].Is_Swimmable = false;
    52.         TileTypes[Tile.typeDic["Wall"]].Is_Flyable = false;
    53.         TileTypes[Tile.typeDic["Wall"]].MapColor = new Color32(255, 0, 0, 255);
    54.     }
    55.  
    Later on, I've set up a function which performs:

    Code (csharp):
    1.  
    2. for (int k = 0; k < TileTypes.Count; k++)
    3.                 {
    4.                     Debug.Log(TileTypes[k].MapColor.ToString());
    5.                 }
    6.  
    The result in the debugger is:

    Code (csharp):
    1.  
    2. RGBA(255, 0, 0, 255)
    3. UnityEngine.Debug:Log(Object)
    4. RGBA(255, 0, 0, 255)
    5. UnityEngine.Debug:Log(Object)
    6. RGBA(255, 0, 0, 255)
    7. UnityEngine.Debug:Log(Object)
    8. RGBA(255, 0, 0, 255)
    9. UnityEngine.Debug:Log(Object)
    10. RGBA(255, 0, 0, 255)
    11. UnityEngine.Debug:Log(Object)
    12.  
    In essence, every tile thinks that it's represented by a solid red pixel, even though I tried to explicitly set them each up to be represented by a different pixel color. For this reason, the only tiles which correctly populate on my game map are the ones which correspond with wall tiles.
    I've been looking at this for over an hour, and have no idea where I've gone wrong. I could use some help.
    It probably won't help any, but I've attached the map image I'm trying to import for posterity.

    Thanks in advance.
     

    Attached Files:

  2. FMark92

    FMark92

    Joined:
    May 18, 2017
    Posts:
    1,243
    Insert a breakpoint and attach a debugger to unity.
    See how the dictionary is populated.

    If I was In your shoes I would just use enums and add the enum as one of the public fields in Tile class.
     
  3. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    Here's a clue: Rearrange your code so that you configure a type of tile other than wall last.

    Now look at lines 24 - 28 in your first block of code. What do you think is happening in this loop?

    Your confusion probably stems from a misunderstanding of reference types. When you create an instance of a reference type, like tile (classes are reference types), you actually create a new object on a piece of memory called the heap. In your variable, you only hold the memory address of the new object. So, in lines 24-28, adding the object to the list multiple times actually just adds the address to the single object multiple times. If you look at the tile in position 0, 1, 2, etc... They all refer to the same single tile on the heap.

    Now coinsider lines 30-53. You should see that you are simply changing the single tile from one type to another so that it ends up in whatever state you configure last.
     
    Last edited: Aug 17, 2017
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,334
    TileType is a class. You're creating a single tileType object (called "blank"), and you're putting it into every single slot of your list.

    So when you do this:

    Code (csharp):
    1. TileTypes[Tile.typeDic["Water"]].MapColor = new Color32(0,0,255,255);
    2. ...
    3. TileTypes[Tile.typeDic["Sand"]].MapColor = new Color32(255, 255, 0, 255);
    You're setting the MapColor of the same TileType object.


    To fix it, just make each tile unique:

    Code (csharp):
    1.  
    2. void InitTiles()
    3.     {
    4.         //Create blank tile types up to the number of available tile types.
    5.         for(int i = 0; i<tileCount;i++)
    6.         {
    7.             TileTypes.Add(new Tile());
    8.         }
    9.  
    10.         ... //as before from here
    11.  
    EDIT: It's a help war, where everyone strikes at the same time.
     
  5. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    @Baste, as usual, your help is much more to the point. This battle might be mine but I concede the war.

    It's late/early? I'll leave you to it!
     
    Baste likes this.
  6. Freecell

    Freecell

    Joined:
    Aug 1, 2017
    Posts:
    4
    That was it. Guess it's a mistake to code at 3AM.

    Thanks for the help.