Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

C#: Arrays with multiple types of data at each point?

Discussion in 'Scripting' started by Edvard-D, Jul 20, 2012.

  1. Edvard-D

    Edvard-D

    Joined:
    Jun 14, 2012
    Posts:
    125
    In the previous language I've worked with (DarkBasic Pro) it was possible to create arrays which could hold several different types of data at each point. What I mean by this is that you could assign an array with a type of the following structure...

    Value1 as Integer
    Name as String
    Value2 as Float
    Value3 as Integer

    ...and then store a value for Value1, String, Value2, and Value3 at every single point along the array (myArray[0] and myArray[1] could each hold Value1, Name, etc). Is this possible or even recommended?

    The reason I ask is that I'm trying to create an array for my tilemap which holds different types of data, such as the GameObject used for that tile and the value that tile holds (if it's a wall, path, etc). I could use several arrays, but it seems like an unnecessary hassle. Maybe there's some other way to go about this that I'm not familiar with?
     
  2. Atin Skrita

    Atin Skrita

    Joined:
    Feb 18, 2011
    Posts:
    94
    Sounds like you want to store multiple values on each index in the array. In this case you would generally create a new type.

    Code (csharp):
    1.  
    2. //create a new type
    3. public class MyNewType
    4. {
    5.    //define all of the values for the class
    6.    public int Value1;
    7.    public string Name;
    8.    public float Value2;
    9.    public int Value3;
    10.    
    11.    //define a constructor for the class
    12.    public MyNewType()
    13.    {
    14.      
    15.    }
    16. }
    17.  
    Then, when you want to use the arrray, simply use you new class.

    Code (csharp):
    1.  
    2. //create an array of your new type
    3. MyNewType[] myClassArray = new MyNewType[numOfElements];
    4.  
    5. //assign Value1 of myClassArray[someIndex] to someValue
    6. myClassArray[someIndex].Value1 = someValue;
    7.  
     
    A_Marraff and StayToasted like this.
  3. ModStoryGames

    ModStoryGames

    Joined:
    Apr 27, 2012
    Posts:
    179
    Code (csharp):
    1.  
    2. public class TileData
    3. {
    4.    public string Name;
    5.    public GameObject go;
    6.    public int ID;
    7. }
    8.  
    9. public class Tilemap : Monobehaviour
    10. {
    11.    private List<TileData> tiles;
    12.    // or
    13.    private TileData[] tiles;
    14.    // or
    15.    private TileData[,] tiles;
    16.    // etc.
    17. }
    18.  
    If you want multiple values inside a single element, you need to encapsulate those values in a class or struct.
     
  4. Meltdown

    Meltdown

    Joined:
    Oct 13, 2010
    Posts:
    5,816
    As Eddy suggests.. rather go for generics. Very efficient.

    List<TileDate> tiles;
     
  5. Edvard-D

    Edvard-D

    Joined:
    Jun 14, 2012
    Posts:
    125
    Thank you to everyone for your responses, and sorry for such a delayed response. Finally found time to start working on this again.

    I think I understand how it all works, but I've run into a bug for some reason. Below is the code I have, with all the irrelevant parts removed. When I run my code an error comes up at the line
    Code (csharp):
    1. terrainArray[arrayPosition].terrainTileValue = objectID;
    (it's toward the bottom) saying that "Object reference not set to an instance of an object." It's obvious I'm doing something wrong but I can't figure out what that is for the life of :(

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5.  
    6. public class terrainData {
    7.     public GameObject terrainGameObject;
    8.     public int terrainTileValue;
    9.    
    10.     public terrainData() {
    11.  
    12.     }
    13. }
    14.  
    15.  
    16. public class TerrainControl : MonoBehaviour {
    17.     terrainData[] terrainArray = new terrainData[1090];
    18.     private int arrayPosition;
    19.    
    20.     public int tileSpacing;
    21.     public int mapWidth;
    22.     public int mapHeight;
    23.     public Transform parentTile;
    24.    
    25.    
    26.     // Use this for initialization
    27.     void Start () {
    28.         tileSpacing = 10;
    29.         mapWidth = 100;
    30.         mapHeight = 100;
    31.        
    32.        
    33.         //Create objects.
    34.         for (int x = 0; x < mapWidth; x++) {
    35.             for (int z = 0; z < mapHeight; z++) {
    36.                 if (x == 0 || x == mapWidth - 1 || z == 0 || z == mapHeight - 1) {
    37.                     CreateTerrainObject(x, z, 1);
    38.                 }
    39.             }
    40.         }
    41.     }
    42.    
    43.  
    44.     //Create Terrain Object
    45.     public void CreateTerrainObject(int x, int z, int objectID) {
    46.         arrayPosition = x * 10 + z;
    47.        
    48.         terrainArray[arrayPosition].terrainTileValue = objectID;
    49.         terrainArray[arrayPosition].terrainGameObject = Instantiate(parentTile, new Vector3(x * tileSpacing, 0, z * tileSpacing), Quaternion.identity) as GameObject;
    50.     }
    51. }
    52.  
     
    Last edited: Sep 17, 2012
  6. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,204
    Recommend using List<> instead array.
    Recommend adding constructor to terrainData that takes gameobject and tile value.
    Recommend replacing "CreateTerrainObject" with call to constructor.

    Then the loop would simplify to:
    Code (csharp):
    1.  
    2.         //Create objects.
    3.  
    4.         for (int x = 0; x < mapWidth; x++) {
    5.             for (int z = 0; z < mapHeight; z++) {
    6.                 if (x == 0 || x == mapWidth - 1 || z == 0 || z == mapHeight - 1) {
    7.                     terrainData.Add(new terraindData(objectID, Instantiate(... all that stuff));
    8.                 }
    9.             }
    10.         }
    11.  
    You'd replace this:
    terrainData[] terrainArray = new terrainData[1090];

    with this:
    List<terrainData> terrainArray = new List<terrainData>();
     
  7. Edvard-D

    Edvard-D

    Joined:
    Jun 14, 2012
    Posts:
    125
    Thanks for the recommendations. Got it working I think and changed a few things that you had pointed out.
     
  8. HydraOrcUnity

    HydraOrcUnity

    Joined:
    Jan 31, 2021
    Posts:
    2
    Code (CSharp):
    1. var data = new object[] { 1, "string", 1.2f, 2 };
    This data format is useful for for sending JSON messages, for example using UltimateJson:

    Code (CSharp):
    1. Debug.Log(JsonObject.Serialise(data));
    Which will result in such array (this approarch generates an object instead of array when serialising classes):
    Code (JavaScript):
    1. [1,"string",1.2,2]
    Also you can store this data in a database like MongoDB
     
    Last edited: Jun 13, 2021
  9. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    I recommend not overdoing OOP and using a struct for the tiles and using arrays to hold the struct instances.
     
  10. Jaimi

    Jaimi

    Joined:
    Jan 10, 2009
    Posts:
    6,204
    Wow, what a necropost. Perhaps after 9 years he has already figured this out. Anyway, I would say that adding a constructor is not overdoing OOP. :)
     
    Kurt-Dekker likes this.
  11. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    It's confusing -- the picture of the OP is wearing a mask, so it looks recent. Plus, if you really want to not overdo OOP, don't even use a struct. Use parallel arrays. Also, no strings. Too many member functions. Use char[].
     
  12. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    Don't look at me, I'm not the one who necro'd this thread, I just missed the original posting date.

    Using a class for a tile in a grid is already overdoing it. It's the wrong data structure for the job.

    Structs aren't OOP and I said overdo, not don't use. Not using OOP isn't always a bad idea, though.
     
  13. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,992
    In C# structs are a speed-hack. C# mostly copied Java and Java doesn't even have what C# calls structs. C# structs don't require extra garbage collection the way classes do, but the drawback of not being able to have a reference to struct objects is pretty bad for most uses.

    In other words, the only reason to say "X should be a struct instead of a class" is because you think it's in a speed-critical area and think that change might make it faster.
     
  14. thorham3011

    thorham3011

    Joined:
    Sep 7, 2017
    Posts:
    25
    My reason for saying this is because it's a bad practice to have heap allocations all over the place for no good reason by making everything a damned class. That c# doesn't give you struct references can indeed be a pain.

    Anyway, I was only talking about not over doing OOP because I've seen it turn into a mess by making every last little thing a class while it's not needed.