3 Errors in Console Please Help

After completing the class 142 and 143 there has been errors in my console for script PathFinder , Enemymover and ObjectPool.
The Error Lines For “Enemy Mover” is at the bottom of PathFinder script copy

Pathfinder c# - error lines 88 in BreathFIrst Meathod = destinationNode.isWalkable = true;
** line 56 in GetNewPath = BreathFirstSearch();**

Script-

public class PathFinder : MonoBehaviour
{
    [SerializeField] Vector2Int startCoordinate;

    public Vector2Int StartCoordinate
    {
        get { return startCoordinate; }
    }

    [SerializeField] Vector2Int destinationCoordinate;

    public Vector2Int DestinationCoordinate
    {
        get { return destinationCoordinate; }
    }


    Node startNode;
    Node destinationNode;
    Node currentSearchNode;

    Queue<Node> frontier = new Queue<Node>(); //QUEUE
    Dictionary<Vector2Int, Node> reached = new Dictionary<Vector2Int, Node>();  //REACHED

    Vector2Int[] directions = { Vector2Int.right, Vector2Int.left, Vector2Int.up, Vector2Int.down };
    GridManager gridManager;
    Dictionary<Vector2Int, Node> grid = new Dictionary<Vector2Int, Node>();

     void Awake()
    {
        gridManager = FindObjectOfType<GridManager>();
        if (gridManager != null)
        {
            grid = gridManager.Grid;
            startNode = grid[startCoordinate];
            destinationNode = grid[destinationCoordinate];
            
        }
    }

    void Start()
    {
        GetNewPath();
    }

    public List<Node> GetNewPath()
    {
        gridManager.ResetNode();

        BreathFirstSearch();
        return BuildPath();
    }

    void ExploreNeighbors()
    {
        List<Node> neighbors = new List<Node>();

        foreach (Vector2Int direction in directions)
        {
            Vector2Int neighborCoordinate = currentSearchNode.coordinates + direction;

            if (grid.ContainsKey(neighborCoordinate))
            {
                neighbors.Add(grid[neighborCoordinate]);
            }
        }

        foreach (Node neighbor in neighbors)
        {
            if (!reached.ContainsKey(neighbor.coordinates) && neighbor.isWalkable)
            {
                neighbor.connectedTo = currentSearchNode;
                reached.Add(neighbor.coordinates, neighbor);
                frontier.Enqueue(neighbor);
            }
        }
    }

    void BreathFirstSearch()
    {
        startNode.isWalkable = true;
        destinationNode.isWalkable = true;

        frontier.Clear();
        reached.Clear();

        bool isRunning = true;

        frontier.Enqueue(startNode);
        reached.Add(startCoordinate, startNode);

        while (frontier.Count > 0 && isRunning)
        {
            currentSearchNode = frontier.Dequeue();
            currentSearchNode.isExplored = true;
            ExploreNeighbors();

            if (currentSearchNode.coordinates == destinationCoordinate)
            {
                isRunning = false;
            }
        }
    }

    List<Node> BuildPath()
    {
        List<Node> path = new List<Node>();
        Node currentNode = destinationNode;

        path.Add(currentNode);
        currentNode.isPath = true;

        while (currentNode.connectedTo != null)
        {
            currentNode = currentNode.connectedTo;
            path.Add(currentNode);
            currentNode.isPath = true;
        }

        path.Reverse();
        return path;
    }

    public bool WillBLockPath(Vector2Int coordinates)
    {
        if (grid.ContainsKey(coordinates))
        {
            bool previousState = grid[coordinates].isWalkable = true;
            
            grid[coordinates].isWalkable = false;
            List<Node> newPath = new List<Node>();
            grid[coordinates].isWalkable = true;

            if (newPath.Count <= 1)
            {
                GetNewPath();
                return true;
            }
        }
        return false;   
    }
}



**ENEMYMOVER  C# - error line 37 in FindPath -path = pathFinder.GetNewPath();**
**                                              line 27 in OnEnable - FindPath();**   

Script=

public class EnemyMover : MonoBehaviour
{

[SerializeField] [Range(0f,5f)] float speed = 1f;

List<Node> path = new List<Node>();

Enemy enemy;
GridManager gridManager;
PathFinder pathFinder;

 void Awake()
{
   enemy = GetComponent<Enemy>();
   gridManager = FindObjectOfType<GridManager>();
   pathFinder = FindObjectOfType<PathFinder>();
}

void OnEnable()
{
    FindPath();
    ReturnToStart();
    StartCoroutine(FollowPath());

}

void FindPath()
{
    path.Clear();
    path = pathFinder.GetNewPath();      
}

void ReturnToStart()
{
    transform.position = gridManager.GetPositionFromCoordinate(pathFinder.StartCoordinate);
}

void FinishPath()
{
    enemy.StealGold();
    gameObject.SetActive(false);
}

IEnumerator FollowPath()
{
    for (int i = 0; i < path.Count; i++)
    {
        Vector3 startPosition = transform.position;
        Vector3 endPosition = gridManager.GetPositionFromCoordinate(path[i].coordinates);
        float travelPercentage = 0f;
        transform.LookAt(endPosition);

        while (travelPercentage < 1f)
        {
            travelPercentage += Time.deltaTime * speed;
            transform.position = Vector3.Lerp(startPosition, endPosition, travelPercentage);
            yield return new WaitForEndOfFrame();
        }
    }

    FinishPath();
}

}

OBJECTPOOL C# - line 40 in EnableObjectInPool - pool[i].SetActive(true);
** line 50 in IEnumerator SpawnEnemy - EnableObjectInPool();**

Script -

public class ObjectPool : MonoBehaviour
{
    [SerializeField] GameObject enemyPrefab;
    [SerializeField][Range(0f ,50f)] int poolSize = 5;
    [SerializeField][Range(0.1f , 30f)] float spawnTimer =1f;

    GameObject[] pool;

     void Awake()
    {
        PopulatePool();
    }
    void Start()
    {
        StartCoroutine(SpawnEnemy());
    }

    void PopulatePool()
    {
        pool = new GameObject[poolSize];

        for (int i = 0; i < pool.Length; i++)
        {
            pool[i] = Instantiate(enemyPrefab, transform);
            pool[i].SetActive(false);
               
        }
    }

    void EnableObjectInPool()
    {
        for (int i = 0; i < pool.Length; i++)
        {
            if (pool[i].activeInHierarchy == false)
            {
                pool[i].SetActive(true);
                return;
            }
        }
    }

    IEnumerator SpawnEnemy()
    {
        while (true)
        {
            EnableObjectInPool();
            yield return new WaitForSeconds(spawnTimer);
        }
    }


}
1 Like

i Managed to fix the errors that were showing up now i have some other bugs popping up,

The Enemy is not following the path and are walking in between tiles also I am not able to place towers to check if the path gets updates or not, also my enemies fly off in air rather than going to the destination node I have already check my code with Gary’s and I don’t know what’s going on. on changing the bool on tiles in inspector to not placeable the color to the tiles still remain white rather than turning grey

Video

Hi Imadity,

Have you already checked all your waypoints in the Hierarchy? Make sure that the ones with the trees are non-walkable.

Since the enemies have an offset, check the position of the enemies. If the position is rounded, e.g. (1, 1), check the children of the enemies. The children must not have an offset. Then check the waypoints the centre of a waypoint should be at a rounded position, e.g. (1, 1).

NullReferenceException means that a reference (“link”) to an instance is missing. Double click on the error message to see to which line in your code it is referring. If you exposed a field in the Inspector, make sure that it’s not empty.

Ill check Waypoints and the offset of the enemies, But the Null Reference Error I dont know what’s missing there, I even compared it Gary’s code I don’t see what’s wrong.

Watch the end of the video I show the Code line and method

Have you already tried to add Debug.Logs to your code to see what is going on during runtime? Try to figure out which part of the if-statement throws the NullReferenceException. That’s impossible to tell just by reading the code because the references get assigned during runtime.

I got the Enemy to in the center of grid, and i placed and a Debug.Log in My OnMouseDown method and there are no updates in the console. how do check if the tiles with trees are set to non walkable?

And the console throws a null reference only when the player clicks to place a turret on tiles with negative axis (could this able because of the tile scrip using the grid with only works on positive
coordinates)

public class Tile : MonoBehaviour
{
    [SerializeField] Tower tower;
    [SerializeField] bool isPlaceable;
    public bool IsPlaceable
    {
        get { return isPlaceable; }
    }

    GridManager gridManager;
    Vector2Int coordinates = new Vector2Int();

    PathFinder pathFinder;

     void Awake()
    {
        pathFinder = FindObjectOfType<PathFinder>();
        gridManager = FindObjectOfType<GridManager>();   
    }

     void Start()
    {
        if (gridManager != null)
        {
            coordinates = gridManager.GetCoordinatesFromPosition(transform.position);

            if (!isPlaceable)
            {
                gridManager.BlockNode(coordinates);
            }    
        }
    }



    void OnMouseDown()
    {
        if(gridManager.GetNode(coordinates).isWalkable && !pathFinder.WillBLockPath(coordinates))
        {
            Debug.Log("Turret placed");
            bool isPlaced = tower.SpawnTower(tower, transform.position);
            isPlaceable = !isPlaceable;
            gridManager.BlockNode(coordinates);

        }
    }
}

That’s important information. Good job on figuring this out.

Take a look at the CreateGrid method and what coordinates for the dictionary get generated there. You’ll see that we start with x = 0 and y = 0 and increment the two values. This means that our CreateGrid method does not create any “coordinates” with negative values.

When you click a tile, the program tries to find the current coordinates in the dictionary.

The solution is to either adjust the for-loop to the scene, or to adjust the scene to the for-loop.

What changes do i have to make in the code soo unity does’nt throw an error, I have tried making changes in the world and if I keep all the tiles positive and try to get the enemy to move to the from start location to end it breaks as it cannot find any tiles after x-14 in the grid

PathFinder

public class PathFinder : MonoBehaviour
{
    [SerializeField] Vector2Int startCoordinate;

    public Vector2Int StartCoordinate
    {
        get { return startCoordinate; }
    }

    [SerializeField] Vector2Int destinationCoordinate;

    public Vector2Int DestinationCoordinate
    {
        get { return destinationCoordinate; }
    }


    Node startNode;
    Node destinationNode;
    Node currentSearchNode;

    Queue<Node> frontier = new Queue<Node>(); //QUEUE

    Dictionary<Vector2Int, Node> reached = new Dictionary<Vector2Int, Node>();  //REACHED

    Vector2Int[] directions = { Vector2Int.right, Vector2Int.left, Vector2Int.up, Vector2Int.down };
    GridManager gridManager;
    Dictionary<Vector2Int, Node> grid = new Dictionary<Vector2Int, Node>();

     void Awake()
    {
        gridManager = FindObjectOfType<GridManager>();
        if (gridManager != null)
        {
            grid = gridManager.Grid;
            startNode = grid[startCoordinate];
            destinationNode = grid[destinationCoordinate];

        }
    }

    void Start()
    {
        GetNewPath();
    }

    public List<Node> GetNewPath()
    {
        gridManager.ResetNode();

        BreathFirstSearch();
        return BuildPath();
    }

    void ExploreNeighbors()
    {
        List<Node> neighbors = new List<Node>();

        foreach (Vector2Int direction in directions)
        {
            Vector2Int neighborCoordinate = currentSearchNode.coordinates + direction;

            if (grid.ContainsKey(neighborCoordinate))
            {
                neighbors.Add(grid[neighborCoordinate]);
            }
        }

        foreach (Node neighbor in neighbors)
        {
            if (!reached.ContainsKey(neighbor.coordinates) && neighbor.isWalkable)
            {
                neighbor.connectedTo = currentSearchNode;
                reached.Add(neighbor.coordinates, neighbor);
                frontier.Enqueue(neighbor);
            }
        }
    }

    void BreathFirstSearch()
    {
        startNode.isWalkable = true;
        destinationNode.isWalkable = true;

        frontier.Clear();
        reached.Clear();

        bool isRunning = true;

        frontier.Enqueue(startNode);
        reached.Add(startCoordinate, startNode);

        while (frontier.Count > 0 && isRunning)
        {
            currentSearchNode = frontier.Dequeue();
            currentSearchNode.isExplored = true;
            ExploreNeighbors();

            if (currentSearchNode.coordinates == destinationCoordinate)
            {
                isRunning = false;
            }
        }
    }

    List<Node> BuildPath()
    {
        List<Node> path = new List<Node>();
        Node currentNode = destinationNode;

        path.Add(currentNode);
        currentNode.isPath = true;

        while (currentNode.connectedTo != null)
        {
            currentNode = currentNode.connectedTo;
            path.Add(currentNode);
            currentNode.isPath = true;
        }

        path.Reverse();
        return path;
    }

    public bool WillBlockPath(Vector2Int coordinates)
    {
        if (grid.ContainsKey(coordinates))
        {
            bool previousState = grid[coordinates].isWalkable = true;
            
            grid[coordinates].isWalkable = false;
            List<Node> newPath = new List<Node>();
            grid[coordinates].isWalkable = true;

            if (newPath.Count <= 1)
            {
                GetNewPath();
                return true;
            }
        }
        return false;   
    }
}

ObjectPool

public class ObjectPool : MonoBehaviour
{
    [SerializeField] GameObject enemyPrefab;
    [SerializeField][Range(0f ,50f)] int poolSize = 5;
    [SerializeField][Range(0.1f , 30f)] float spawnTimer =1f;

    GameObject[] pool;

     void Awake()
    {
        PopulatePool();
    }
    void Start()
    {
        StartCoroutine(SpawnEnemy());
    }

    void PopulatePool()
    {
        pool = new GameObject[poolSize];

        for (int i = 0; i < pool.Length; i++)
        {
            pool[i] = Instantiate(enemyPrefab, transform);
            pool[i].SetActive(false);
               
        }
    }

    void EnableObjectInPool()
    {
        for (int i = 0; i < pool.Length; i++)
        {
            if (pool[i].activeInHierarchy == false)
            {
                pool[i].SetActive(true);
                return;
            }
        }
    }

    IEnumerator SpawnEnemy()
    {
        while (true)
        {
            EnableObjectInPool();
            yield return new WaitForSeconds(spawnTimer);
        }
    }
}

GridManager

public class GridManager : MonoBehaviour
{
    [Tooltip("World Grid Size Should Match UnityEditor snap settings.")]
    [SerializeField] int unityGridSize = 10;

    public int UnityGridSize
    {
        get { return unityGridSize; }
    }
     
    [SerializeField] Vector2Int gridSize;
    Dictionary<Vector2Int , Node> grid = new Dictionary<Vector2Int, Node>();

    public Dictionary<Vector2Int, Node> Grid
    {
        get { return grid; }
    }

    void Awake()
    {
        CreateGrid();
    }

    public Node GetNode(Vector2Int coordinates)
    {
        if (grid.ContainsKey(coordinates))
        {
            return grid[coordinates];
        }
        return null;
    }

    public void BlockNode(Vector2Int coordinates)
    {
        if (grid.ContainsKey(coordinates))
        {
            grid[coordinates].isWalkable = false;
        }
    }

    public void ResetNode()
    {
        foreach (KeyValuePair<Vector2Int, Node> entry in grid)
        {
            entry.Value.connectedTo = null;
            entry.Value.isExplored = false;
            entry.Value.isPath = false;
            
        }
    }

    public Vector2Int GetCoordinatesFromPosition(Vector3 position)
    {
        Vector2Int coordinates = new Vector2Int();   
        coordinates.x = Mathf.RoundToInt(position.x / unityGridSize);
        coordinates.y = Mathf.RoundToInt(position.z / unityGridSize);
        
        return coordinates;
    }

    public Vector3 GetPositionFromCoordinates(Vector2Int coordinates)
    {
        Vector3 position = new Vector3();
        position.x = coordinates.x * unityGridSize;
        position.z = coordinates.y * unityGridSize;

        return position;
    }

    void CreateGrid()
    {
        for (int x = 0; x < gridSize.x; x++)
        {
            for (int y = 0; y < gridSize.y; y++)
            {
                Vector2Int coordinates = new Vector2Int(x, y);
                grid.Add(coordinates, new Node(coordinates , true));
                
            }
        }
    }
}

Did you fix the problem with the negative coordinates? Your terrain and the coordinates in your screenshot look fine.

The first error message tells us that the concerning tile is (17, 7). These coordinates were not found as a key in the dictionary.

  1. Where did you define the startNode value and the destinationNode value? You have to assign the values/objects in the Inspector of the relevant game object.

  2. And what values did you use for gridSize in the Inspector? The values must be the hightest coordinates values in your case, not the actual size in World Units. For example, in your screenshot, the top right tile of your grid might be (17, 10), so your gridSize is supposed to be set to (17, 10).

How are you getting on with this, @Imadity?

I fixed this with some help but the problem was my Grid size allowed only some of the tiles to be accessible and when clicked on tiles outside the gridsize unity would throw a null reference as the tile was not present tin the dictionary

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

Privacy & Terms