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

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:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WorldManager3 : MonoBehaviour
{
    public Vector2Int WorldSize = new Vector2Int(100, 75);
    public Tile[,] World = new Tile[100, 75];

    private void Start()
    {
        for (int i = 0, z = 0; z < WorldSize.x; z++)
        {
            for (int x = 0; x < WorldSize.y; x++)
            {
                Debug.Log(new Vector3(x - WorldSize.x, World[x, z].LandHeight, z - WorldSize.y));
                i++;
            }
        }
    }
}

[System.Serializable]
public class Tile
{
    public int LandHeight = 1;
    public int WaterHeight = 1;
}

Does someone know whats hapening?

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Steps to success:

  • Identify what is null
  • Identify why it is null
  • Fix that

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

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WorldManager3 : MonoBehaviour
{
    public Vector2Int WorldSize = new Vector2Int(100, 75);
    public Tile[] World = new Tile[100];

    private void Start()
    {
        for (int i = 0, z = 0; z < WorldSize.x; z++)
        {
            for (int x = 0; x < WorldSize.y; x++)
            {
                Debug.Log(new Vector3(x - WorldSize.x, World[x].LandHeight, z - WorldSize.y));
                i++;
            }
        }
    }
}

[System.Serializable]
public class Tile
{
    public int LandHeight = 1;
    public int WaterHeight = 1;
}

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.

1 Like

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?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WorldManager3 : MonoBehaviour
{
    public Vector2Int WorldSize = new Vector2Int(100, 75);
    public Tile[,] World = new Tile[100, 75];

    private void Start()
    {
        for (int i = 0, y = 0; y < WorldSize.y; y++)
        {
            for (int x = 0; x < WorldSize.x; x++)
            {
                Debug.Log(new Vector3(x - WorldSize.x, World[x, y].LandHeight, y - WorldSize.y));
                i++;
            }
        }
    }
}

[System.Serializable]
public class Tile
{
    public int LandHeight = 1;
    public int WaterHeight = 1;
}

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.

2 Likes

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.

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:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WorldManager3 : MonoBehaviour
{
    public Vector2Int WorldSize = new Vector2Int(100, 75);
    public Tile[][] World = new Tile[100][75];

    private void Start()
    {
        for (int i = 0, y = 0; y < WorldSize.y; y++)
        {
            for (int x = 0; x < WorldSize.x; x++)
            {
                Debug.Log(new Vector3(x - WorldSize.x, World[x][y].LandHeight, y - WorldSize.y));
                i++;
            }
        }
    }
}

[System.Serializable]
public class Tile
{
    public int LandHeight = 1;
    public int WaterHeight = 1;
}

Thanks! It works!
I now use this code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class WorldManager3 : MonoBehaviour
{
    public Vector2Int WorldSize = new Vector2Int(100, 75);
    public Tile[,] World = new Tile[100,75];

    void Start()
    {
        for (int i = 0, y = 0; y < WorldSize.y; y++)
        {
            for (int x = 0; x < WorldSize.x; x++)
            {
                World[x, y] = new Tile();
            }
        }

        for (int i = 0, y = 0; y < WorldSize.y; y++)
        {
            for (int x = 0; x < WorldSize.x; x++)
            {
                Debug.Log(new Vector3(x - WorldSize.x, World[x,y].LandHeight, y - WorldSize.y));
                i++;
            }
        }
    }
}

[System.Serializable]
public class Tile
{
    public int LandHeight = 1;
    public int WaterHeight = 1;
}

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>()

1 Like

@machinebouwclub Why are you using the “i” variable at all? You never use it.

I simplefied the code down to the error, but my real code is longer