Search Unity

Inspector not showing public variables

Discussion in 'Scripting' started by patgiok, Aug 29, 2019.

  1. patgiok

    patgiok

    Joined:
    Aug 17, 2019
    Posts:
    3
    Hi, new to game making and unity!

    I've spent way more time than I should have trying to fix this so hopefully someone knows.
    I'm trying to get the inspector to show the public variables of my tile class that is procedurally generated so that I can modify them in the inspector.

    I've tried [SerializeField] before variables, [Serializeable] before the class, made sure its public, not static etc and read up a few Unity Manual pages on serialization, and the googles.
    I noticed that member variables of my other classes show up in its script component, which leads me to my question: Does my tile need a script to show variables in the inspector? I'm trying to keep it purely as a data class with a callback for when things change.

    Also feel free to critique the code, and mention design patterns I should try to use. I've been kind of following Quill18Creates' base building tutorial.
    Also side question, how can I decouple the sprites and sprite renderer from my WorldController class?

    Thanks!
    https://imgur.com/a/cJAwCNY

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System;
    5.  
    6. public enum TileType
    7. {
    8.     Water,
    9.     Dirt,
    10.    
    11.     Road,
    12.     Grass,
    13.     Farm,
    14.     RockWall,
    15.     Building
    16. }
    17.  
    18. public class Tile
    19. {
    20.  
    21.     // Data for map gen / effects
    22.     [SerializeField]
    23.     public float Elevation { get; set; }
    24.     [SerializeField]
    25.     public float Moisture { get; set; }
    26.  
    27.     //callback func whenever tiletype gets set
    28.     Action<Tile> cbTileTypeChanged;
    29.  
    30.     // Default base tile type
    31.     TileType type = TileType.Water;
    32.     // Constructor
    33.     public TileType Type
    34.     {
    35.         get
    36.         {
    37.             return type;
    38.         }
    39.         set
    40.         {
    41.             //can optimize take out instance var
    42.             TileType oldType = type;
    43.             type = value;
    44.            
    45.             //Call the callback and let things know we've changed
    46.             if (cbTileTypeChanged != null && oldType != type)
    47.                 cbTileTypeChanged(this);
    48.         }
    49.     }
    50.  
    51.  
    52.     World world;
    53.     public int x { get; protected set; }
    54.     public int y { get; protected set; }
    55.  
    56.     public Tile(World world, int x, int y)
    57.     {
    58.         this.world = world;
    59.         this.x = x;
    60.         this.y = y;
    61.     }
    62.    
    63.  
    64.  
    65.     public void RegisterTileTypeChangedCallback(Action<Tile> callbackfunc)
    66.     {
    67.         cbTileTypeChanged += callbackfunc;
    68.     }
    69.  
    70.  
    71.  
    72.     public void UnregisterTileTypeChangedCallback(Action<Tile> callbackfunc)
    73.     {
    74.         cbTileTypeChanged -= callbackfunc;
    75.     }
    76. }
    77.  
    Code (CSharp):
    1. using System.Collections;
    2. using System;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class World : MonoBehaviour
    7. {
    8.  
    9.     Tile[,] tiles;
    10.     public int width;
    11.     public int height;
    12.    
    13.     public World(int width = 50, int height = 50)
    14.     {
    15.         this.width = width;
    16.         this.height = height;
    17.  
    18.         tiles = new Tile[width, height];
    19.         for (int x = 0; x < width; x++)
    20.         {
    21.             for (int y = 0; y < height; y++)
    22.             {
    23.                 tiles[x, y] = new Tile(this, x, y);
    24.                 tiles[x, y].Type = TileType.Water;
    25.  
    26.             }
    27.  
    28.         }
    29.     }
    30.  
    31.     public Tile GetTileAt(int x, int y)
    32.     {
    33.         if(x > width || x < 0 || y > height || y < 0)
    34.         {
    35.             return null;
    36.         }
    37.         return tiles[x, y];
    38.     }
    39. }
    40.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WorldController : MonoBehaviour
    6. {
    7.     public static WorldController Instance;
    8.  
    9.     public Sprite dirtSprite;
    10.     public Sprite grassSprite;
    11.     public Sprite waterSprite;
    12.     public Sprite rockWallSprite;
    13.     Dictionary<Tile, GameObject> tileGameObjectMap;
    14.  
    15.     public World world { get; protected set; }
    16.  
    17.     // Start is called before the first frame update
    18.     void Start()
    19.     {
    20.         Instance = this;
    21.         world = new World();
    22.  
    23.         tileGameObjectMap = new Dictionary<Tile, GameObject>();
    24.         for (int x = 0; x < world.width; x++)
    25.         {
    26.             for (int y = 0; y < world.height; y++)
    27.             {
    28.                 Tile tile_data = world.GetTileAt(x, y);
    29.                 GameObject tile_go = new GameObject();
    30.  
    31.                 tileGameObjectMap.Add(tile_data, tile_go);
    32.                 tile_go.name = "Tile: " + x + ", " + y;
    33.                 tile_go.transform.position = new Vector3(tile_data.x, tile_data.y, 0);
    34.                 tile_go.transform.SetParent(this.transform, true);
    35.  
    36.                 tile_go.AddComponent<SpriteRenderer>();
    37.                 tile_go.GetComponent<SpriteRenderer>().sprite = waterSprite;
    38.                 tile_data.RegisterTileTypeChangedCallback(onTileTypeChanged);
    39.             }
    40.  
    41.         }
    42.         GenerateMap();
    43.     }
    44.  
    45.  
    46.     public float dirtHeight = 0.1f;
    47.     public float grassHeight = 0.16f;
    48.     public float hillHeight = 0.4f;
    49.     public float mountainHeight = 0.6f;
    50.  
    51.  
    52.     //Generate Map
    53.     public void GenerateMap()
    54.     {
    55.         //world
    56.  
    57.         float noiseResolution = 0.161f;
    58.         float noiseScale = 1f;
    59.         for (int x = 0; x < world.width; x++)
    60.         {
    61.             for (int y = 0; y < world.height; y++)
    62.             {
    63.                 Tile t = Instance.world.GetTileAt(x, y);
    64.                 float n = Mathf.PerlinNoise( x * 0.5f, y * 0.5f);
    65.                 Debug.Log(n);
    66.                 t.Elevation += n;
    67.  
    68.                 if (t.Elevation >= dirtHeight)
    69.                 {
    70.                     t.Type = TileType.Dirt;
    71.                 }
    72.                 else if (t.Elevation >= grassHeight){
    73.                     t.Type = TileType.Grass;
    74.                 }
    75.                 else if (t.Elevation >= mountainHeight)
    76.                 {
    77.                     t.Type = TileType.RockWall;
    78.                 }
    79.             }
    80.         }
    81.  
    82.     }
    83.  
    84.  
    85.  
    86.  
    87.  
    88.  
    89.  
    90.  
    91.  
    92.  
    93.     // Update is called once per frame
    94.     void Update()
    95.     {
    96.        
    97.     }
    98.  
    99.     public void onTileTypeChanged(Tile tile_data)
    100.     {
    101.         if(tileGameObjectMap.ContainsKey(tile_data) == false)
    102.         {
    103.             Debug.LogError("tileGameObjectMap doesn't contain this key");
    104.             return;
    105.         }
    106.         GameObject tile_go = tileGameObjectMap[tile_data];
    107.         if(tile_go == null)
    108.         {
    109.             Debug.LogError("No GameObject for this tile");
    110.             return;
    111.         }
    112.  
    113.         if(tile_data.Type == TileType.Grass)
    114.         {
    115.             tile_go.GetComponent<SpriteRenderer>().sprite = grassSprite;
    116.            
    117.             return;
    118.         }
    119.         if(tile_data.Type == TileType.Dirt)
    120.         {
    121.             tile_go.GetComponent<SpriteRenderer>().sprite = dirtSprite;
    122.             return;
    123.         }
    124.         if (tile_data.Type == TileType.RockWall)
    125.         {
    126.             tile_go.GetComponent<SpriteRenderer>().sprite = rockWallSprite;
    127.             return;
    128.         }
    129.         if (tile_data.Type == TileType.Water)
    130.         {
    131.             tile_go.GetComponent<SpriteRenderer>().sprite = waterSprite;
    132.             return;
    133.         }
    134.  
    135.  
    136.  
    137.     }
    138. }
    139.  
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    Properties don't get serialized.

    Perhaps look into either writing a custom inspector, or maybe get something like Odin Inspector from the asset store that will handle them (and other stuff).
     
    Dextozz likes this.
  3. Dextozz

    Dextozz

    Joined:
    Apr 8, 2018
    Posts:
    493
    Yup, as @StarManta mentioned, properties don't get serialized. A quick workaround would be to simply make it a public variable instead of a property. Simply remove the { get; set; } from the properties you want to serialize.
     
  4. patgiok

    patgiok

    Joined:
    Aug 17, 2019
    Posts:
    3
    thanks for the replies,
    I've tried having them as just public variables too but the generated tiles don't show any variables in the inspector. I know they're holding the variables as they change sprites based on the height. Right now I'm trying to get a text mesh generated as a child that will just print it on screen. xd
     
  5. Dextozz

    Dextozz

    Joined:
    Apr 8, 2018
    Posts:
    493
    You also need [System.Serializable] in front of your class. Take a look at this video:
     
    ozgurgirgin likes this.
  6. patSilva

    patSilva

    Joined:
    Mar 25, 2019
    Posts:
    27
    To show classes on the inspector you have to serialize them by adding the [System.Serializable] attribute.
    your tile script should have

    Code (CSharp):
    1.  
    2. [System.Serializable]
    3. public class Tiles
    4. {
    5. // all your code
    6.  
    7. }
    SORRY THIS WONT WORK because you are doing a 2d Array [,] you have it will not show on the inspector. You will need to create a script that handle would handle it properly. I would suggest changing the 2D array to a one dimensional collection. Row and column indexes can be figured mathematically if you have the max column.

    You can figure out the row and column from an index with the following math:
    int row = index / maxColumn; // make sure maxColumn is an int
    int column = index % maxColumn; // this will give a remainder always between 0 and maxColumn

    or, you have x,y coordinate to find the proper index
    index = (row * maxColumn) + column;


    I use this method for my tile maps so I can still see them in the inspector and still access them with a x,y coordinate mentality. So the TileMap will be a List<Tile> and then I will use the math above to access the values.
     
    Last edited: Aug 30, 2019