craftomega
craftomega

Reputation: 31

Unity 3d Argument out of range

This script is meant to find the next node in a grid closest to the "destination". The code works once and then informs me "Argument out of range Exception. Parameter name: Index." I believe the error is on "tempNode = currentPath[m_index];". But after banging my head against the keyboard for and hour I am not sure anymore. The currentPath aways has at least 1 item in it, and it throws the error no matter how many are in it.

Unity does not inform me specifically where the error is, only that it is a List error. Thoughts?

I know it is coming from this part of the code, but I have included the whole code bellow it.

else 
{
    pathFound = false;
    if (currentPath.Capacity > 0 && pathFound == false)
    {
        int m_index = (currentPath.Count - 1);
        List<PathNodes> tempNodeList;
        PathNodes tempNode;
        tempNode = currentPath[m_index];
        tempNodeList = tempNode.connections;
        if (tempNodeList == null)
        {
            Debug.Log("Paths not built");
        }
        else
        {
            currentPath.Add(GetNextNode(tempNodeList, destinationNode.gameObject).GetComponent<PathNodes>());
            EditorUtility.SetDirty(this);
            tempNode = null;
            tempNodeList = null;
        }
    }
}

Whole code

[SerializeField] public GameObject currentNode;
[SerializeField] public GameObject destinationNode;
[SerializeField] public GameObject destination;
[SerializeField] public GameObject[] allPathNodes;
public List<PathNodes> currentPath;
public List<PathNodes> avoidPath;

void findPath()
{
    bool pathFound;

    if(allPathNodes == null)
    {
        allPathNodes = GameObject.FindGameObjectsWithTag("PathNode");
    }


    if (currentPath.Capacity == 0)
    {
        currentPath.Add(GetClosestNode(allPathNodes, gameObject).GetComponent<PathNodes>());
        EditorUtility.SetDirty(this);
    }

    if (currentNode == null && currentPath[0] != null)
    {
        currentNode = currentPath[0].gameObject;
    }

    if (destinationNode == null)
    {
        if (destination == null)
        {
            Debug.Log("Destination not set");
        }
        else
        {
            destinationNode = GetClosestNode(allPathNodes, destination);
            EditorUtility.SetDirty(this);
        }
    }
    if (currentPath[currentPath.Capacity - 1].gameObject == destinationNode)
    {
        pathFound = true;
    }
    else 
    {
        pathFound = false;
        if (currentPath.Capacity > 0 && pathFound == false)
        {
            int m_index = (currentPath.Count - 1);
            List<PathNodes> tempNodeList;
            PathNodes tempNode;
            tempNode = currentPath[m_index];
            tempNodeList = tempNode.connections;
            if (tempNodeList == null)
            {
                Debug.Log("Paths not built");
            }
            else
            {
                currentPath.Add(GetNextNode(tempNodeList, destinationNode.gameObject).GetComponent<PathNodes>());
                EditorUtility.SetDirty(this);
                tempNode = null;
                tempNodeList = null;
            }
        }
    }

Upvotes: 0

Views: 280

Answers (1)

Ron Beyer
Ron Beyer

Reputation: 11273

The problem is using List<T>.Capacity. Capacity, as stated in the documentation is always greater than or equal to the number of items in the list, Count.

Capacity is the number of elements the list can hold without the backing store (an array) needing to be resized. Since a resize operation is expensive (a new array is created an existing elements are copied, before the old array is destroyed), Capacity can be used to determine how much data can be swapped in/out of a list in a high performance manner (you can also define an initial capacity when you construct the List).

So the problem begins on this line:

if (currentPath.Capacity == 0)

With the error you are getting probably being thrown on this line, since Capacity is probably greater than the current Count:

if (currentPath[currentPath.Capacity - 1].gameObject == destinationNode)

And the fix is to replace Capacity with Count. Same goes for this line:

if (currentPath.Capacity > 0 && pathFound == false)

In order to make Capacity equal Count, you need to do a List<T>.TrimExcess() call to resize the array, but be aware that this is a much more expensive operation than just keeping the small amount of excess and using Count instead.

Upvotes: 1

Related Questions