Problem with NullReferenceException in the course

Hi all. I’ve been following Hugo for a while now and this lecture was a logical step. I have followed everything “by the book” but when I start to test the game in this lecture I get

NullReferenceException: Object reference not set to an instance of an object
Unit.Start () (at Assets/Scripts/Unit.cs:18)

for this line

gridPosition = LevelGrid.Instance.GetGridPosition(transform.position);

and this error

NullReferenceException: Object reference not set to an instance of an object
Unit.Update () (at Assets/Scripts/Unit.cs:39)

for this line

GridPosition newGridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
if (newGridPosition != gridPosition) {
// Unit changed Grid Position
LevelGrid.Instance.UnitMovedGridPosition(this, gridPosition, newGridPosition);
gridPosition = newGridPosition;
}

any idea what am I missing?

Found the issue but now have another. The issue was in LevelGrid.cs I did not actually set the instance on awake. but now it only works for bottom row. “Height” grid spaces are not working. Any idea?

I’m not entirely sure what your meaning with the “Height”… I’m assuming you’re not meaning the floor (from the bonus lectures, multi-floor play).

Are you saying that it’s only retrieving gridPositions with a gridPosition.z value of 0 (the first “row”)?

Let’s take a look at your LevelGrid.cs and your GridSystem.cs scripts.

Yes thats prob it. Here are the codes.

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

public class LevelGrid : MonoBehaviour {

    public static LevelGrid Instance { get; private set; }

    [SerializeField] private Transform gridDebugObjectPrefab;
    private GridSystem gridSystem;

    private void Awake() {

        if (Instance != null) {
            Debug.LogError("There is more than one LevelGrid!" + transform + " - " + Instance);
            Destroy(gameObject);
            return;
        }

        Instance = this;

        gridSystem = new GridSystem(10, 10, 2f);
        gridSystem.CreateDebugObjects(gridDebugObjectPrefab);
    }


    public void AddUnitAtGridPosition(GridPosition gridPosition, Unit unit) {
        GridObject gridObject = gridSystem.GetGridObject(gridPosition);
        gridObject.AddUnit(unit);
    }

    public List<Unit> GetUnitListAtGridPosition(GridPosition gridPosition) {
        GridObject gridObject = gridSystem.GetGridObject(gridPosition);
        return gridObject.GetUnitList();
    }

    public void RemoveUnitAtGridPosition(GridPosition gridPosition, Unit unit) {
        GridObject gridObject = gridSystem.GetGridObject(gridPosition);
        gridObject.RemoveUnit(unit);
    }

    public void UnitMovedGridPosition(Unit unit, GridPosition fromGridPosition, GridPosition toGridPosiiton) {
        RemoveUnitAtGridPosition(fromGridPosition, unit);

        AddUnitAtGridPosition(toGridPosiiton, unit);
    }

    public GridPosition GetGridPosition(Vector3 worldPosition) => gridSystem.GetGridPosition(worldPosition);
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GridSystem {


    private int width;
    private int height;
    private float cellSize;
    private GridObject[,] gridObjectArray;

    public GridSystem(int width, int height, float cellSize) {
        this.width = width;
        this.height = height;
        this.cellSize = cellSize;

        gridObjectArray = new GridObject[width, height];
        for (int x = 0; x < width; x++) { 
            for (int z = 0; z < height; z++) {
                GridPosition gridPosition = new GridPosition(x, z);
                gridObjectArray[x, z] = new GridObject(this, gridPosition);
            }
        }
        
    }

    public Vector3 GetWorldPosition(GridPosition gridPosition) {
        return new Vector3(gridPosition.x, 0, gridPosition.z) * cellSize;
    }
    
    public GridPosition GetGridPosition(Vector3 worldPosition) {
        return new GridPosition(
                Mathf.RoundToInt(worldPosition.x / cellSize),
                Mathf.RoundToInt(worldPosition.y / cellSize)
            );
    }
    
    public void CreateDebugObjects(Transform debugPrefab) {
        for (int x = 0; x < width; x++) {
            for (int z = 0; z < height; z++) {
                GridPosition gridPosition = new GridPosition(x, z);

                Transform debugTransform = GameObject.Instantiate(debugPrefab, GetWorldPosition(gridPosition), Quaternion.identity);
                GridDebugObject gridDebugObject = debugTransform.GetComponent<GridDebugObject>();
                gridDebugObject.SetGridObject(GetGridObject(gridPosition));
            }
        }
    }

    public GridObject GetGridObject(GridPosition gridPosition) {
        return gridObjectArray[gridPosition.x, gridPosition.z];
    }

}

This looks correct. Are the GridDebugObjects populating along the full grid?

One more check, paste in your GridPosition.cs

For code pastes, you use the single ` for inline code, for example `code` will become code
For code blocks, use three ``` on a line by themselves at the beginning and end of the code block
so
```
This is some code
In a block
```
becomes

This is some code
In a block

I edited your prior posts to reflect this. If you edit the post, you can see what I’ve done.

Thanks.


Maybe you can see it here more clearly. it registers second unit in first row. other rows dont work.
Here is code:




using System;

public struct GridPosition : IEquatable<GridPosition> {
    public int x;
    public int z;

    public GridPosition(int x, int z) {

        this.x = x;
        this.z = z;
    }

    public override bool Equals(object obj) {
        return obj is GridPosition position &&
               x == position.x &&
               z == position.z;
    }

    public bool Equals(GridPosition other) {
        return this == other;
    }

    public override int GetHashCode() {
        return HashCode.Combine(x, z);
    }

    public override string ToString() {
        return $"x: {x}; z: {z}";
    }

    public static bool operator ==(GridPosition a, GridPosition b) {
        return a.x == b.x && a.z == b.z ;
    }

    public static bool operator !=(GridPosition a, GridPosition b) 
        { return !(a == b); }

}

The problem is here. See if you can spot it. You’re using worldPosition.y instead of worldPosition.z (sorry for poaching your post, @Brian_Trotter)

Yes I can… Thank you very much. Looks like I auto-complete it and did not double check.

prob was in worldPosition.y
correct func would be
Mathf.RoundToInt(worldPosition.z / cellSize)

Thank you very much, got it running again!

On a unrelated note - is it possible to get private coaching from someone here at gamedev.tv? I have a problem on a different project I was working and I literally quit the project and went back to learning because of it. It would be nice to have an option for 1 on 1 coaching, for a fee of course, just to be able to pass some roadblock easier. I have 2 small kids and 2 jobs so my time is limited and I can’t really afford going through ton of Unity docs when I don’t really know what it is I am searching for :smiley:

Finally spotted it. GetGridPosition() in GridSystem, you’re using worldPosition.y instead of worldPosition.z
Apologies for not catching that on the first go. Once I saw the picture, it spellled out what the problem must be.

LOL, somehow my answer came a bit late. Didn’t noticed that @bixarrio already had it well in hand.

That’s ok. Thank you very much for quick response to my problem. I know it looks silly but I am still quite new to it all and simple mistakes like this still do happen from time to time.

Yep, and that one is an easy mistake to make. Don’t let the fancy Teaching Assistant title fool ya. Us instructors make mistakes too. :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms