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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Resolved NullReferenceException when trying to get value of position in 2D array

Discussion in 'Scripting' started by machinebouwclub, Mar 9, 2022.

  1. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    I am trying to get the value LandHeight in the 2D Tile-array. I tried a 1D array and it works but with a 2D array i get this error message:

    NullReferenceException: Object reference not set to an instance of an object
    WorldManager3.Start () (at Assets/ScriptableObjects/WorldManager3.cs:16)

    Here's the code:
    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5.  
    6. public class WorldManager3 : MonoBehaviour
    7. {
    8.     public Vector2Int WorldSize = new Vector2Int(100, 75);
    9.     public Tile[,] World = new Tile[100, 75];
    10.  
    11.     private void Start()
    12.     {
    13.         for (int i = 0, z = 0; z < WorldSize.x; z++)
    14.         {
    15.             for (int x = 0; x < WorldSize.y; x++)
    16.             {
    17.                 Debug.Log(new Vector3(x - WorldSize.x, World[x, z].LandHeight, z - WorldSize.y));
    18.                 i++;
    19.             }
    20.         }
    21.     }
    22. }
    23.  
    24. [System.Serializable]
    25. public class Tile
    26. {
    27.     public int LandHeight = 1;
    28.     public int WaterHeight = 1;
    29. }
    30.  
    Does someone know whats hapening?
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
  3. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    Hi!
    Thanks for your reaction! But is can't find whats the problem with you're metheot.
    Becouse the code works well in a 1D array
    Code with 1D array
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WorldManager3 : MonoBehaviour
    6. {
    7.     public Vector2Int WorldSize = new Vector2Int(100, 75);
    8.     public Tile[] World = new Tile[100];
    9.  
    10.     private void Start()
    11.     {
    12.         for (int i = 0, z = 0; z < WorldSize.x; z++)
    13.         {
    14.             for (int x = 0; x < WorldSize.y; x++)
    15.             {
    16.                 Debug.Log(new Vector3(x - WorldSize.x, World[x].LandHeight, z - WorldSize.y));
    17.                 i++;
    18.             }
    19.         }
    20.     }
    21. }
    22.  
    23. [System.Serializable]
    24. public class Tile
    25. {
    26.     public int LandHeight = 1;
    27.     public int WaterHeight = 1;
    28. }
     
  4. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    There's something weird with your coordinates/indexes.
    for (int i = 0, z = 0; z < WorldSize.x; z++)

    In this line, you are using z < WorldSize.x as the boundary of the loop, but
    World[x, z].LandHeight

    here you use z to access the second index of the array. You are probably over running the bounds this way.
     
    Bunny83 likes this.
  5. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    Hi! Thanks for your reaction!
    I tried it agen with the code below, but it still doesn't work. Or wasn't this what you ment?

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WorldManager3 : MonoBehaviour
    6. {
    7.     public Vector2Int WorldSize = new Vector2Int(100, 75);
    8.     public Tile[,] World = new Tile[100, 75];
    9.  
    10.     private void Start()
    11.     {
    12.         for (int i = 0, y = 0; y < WorldSize.y; y++)
    13.         {
    14.             for (int x = 0; x < WorldSize.x; x++)
    15.             {
    16.                 Debug.Log(new Vector3(x - WorldSize.x, World[x, y].LandHeight, y - WorldSize.y));
    17.                 i++;
    18.             }
    19.         }
    20.     }
    21. }
    22.  
    23. [System.Serializable]
    24. public class Tile
    25. {
    26.     public int LandHeight = 1;
    27.     public int WaterHeight = 1;
    28. }
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    Who is filling this data out for you?

    If you're not filling it out in code, then World[,] is just an array of nulls, as Tile[,] is a nullable type.

    You need to allocate each individual tile and stick it into each position in that 2D array, because Unity's serialization does NOT support filling 2D arrays.

    EDIT for Wallace's next post:

    Pretty sure both jagged and 2D arrays are not serialized by Unity.
     
    Bunny83 and machinebouwclub like this.
  7. WallaceT_MFM

    WallaceT_MFM

    Joined:
    Sep 25, 2017
    Posts:
    394
    Try using a
    Tile[][]
    instead of a
    Tile[,]
    , might be that the rectangular array isn't initialized like you think it should be.
    If that's the case, then you'll need to populate the World array before using it. Unity does this magically with public arrays, but might not do it for multidimensional arrays, only jagged arrays.
     
  8. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    I used the code below, but i get this error:

    Assets\ScriptableObjects\WorldManager3.cs(8,43): error CS0178: Invalid rank specifier: expected ',' or ']'

    The code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WorldManager3 : MonoBehaviour
    6. {
    7.     public Vector2Int WorldSize = new Vector2Int(100, 75);
    8.     public Tile[][] World = new Tile[100][75];
    9.  
    10.     private void Start()
    11.     {
    12.         for (int i = 0, y = 0; y < WorldSize.y; y++)
    13.         {
    14.             for (int x = 0; x < WorldSize.x; x++)
    15.             {
    16.                 Debug.Log(new Vector3(x - WorldSize.x, World[x][y].LandHeight, y - WorldSize.y));
    17.                 i++;
    18.             }
    19.         }
    20.     }
    21. }
    22.  
    23. [System.Serializable]
    24. public class Tile
    25. {
    26.     public int LandHeight = 1;
    27.     public int WaterHeight = 1;
    28. }
     
  9. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    Thanks! It works!
    I now use this code:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class WorldManager3 : MonoBehaviour
    6. {
    7.     public Vector2Int WorldSize = new Vector2Int(100, 75);
    8.     public Tile[,] World = new Tile[100,75];
    9.  
    10.     void Start()
    11.     {
    12.         for (int i = 0, y = 0; y < WorldSize.y; y++)
    13.         {
    14.             for (int x = 0; x < WorldSize.x; x++)
    15.             {
    16.                 World[x, y] = new Tile();
    17.             }
    18.         }
    19.  
    20.         for (int i = 0, y = 0; y < WorldSize.y; y++)
    21.         {
    22.             for (int x = 0; x < WorldSize.x; x++)
    23.             {
    24.                 Debug.Log(new Vector3(x - WorldSize.x, World[x,y].LandHeight, y - WorldSize.y));
    25.                 i++;
    26.             }
    27.         }
    28.     }
    29. }
    30.  
    31. [System.Serializable]
    32. public class Tile
    33. {
    34.     public int LandHeight = 1;
    35.     public int WaterHeight = 1;
    36. }
     
  10. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,963
    Are these Unity
    Tile
    objects, as in the things that you put in a Tilemap??

    If so you can NEVER make them with
    new
    ... they are only half made:
    new
    will not create the native engine side so they will not function properly.

    You can either load them as assets off disk (
    Resources.Load<Tile>()
    ), or else make them with
    ScriptableObject.CreateInstance<Tile>()
     
    Bunny83 likes this.
  11. JeffDUnity3D

    JeffDUnity3D

    Unity Technologies

    Joined:
    May 2, 2017
    Posts:
    14,446
    @machinebouwclub Why are you using the "i" variable at all? You never use it.
     
  12. machinebouwclub

    machinebouwclub

    Joined:
    Apr 14, 2021
    Posts:
    9
    I simplefied the code down to the error, but my real code is longer