Search Unity

Pooling Prefab Becomes Null?

Discussion in 'Scripting' started by JamieRoss95, May 13, 2019.

  1. JamieRoss95

    JamieRoss95

    Joined:
    Apr 5, 2016
    Posts:
    28
    [SOLVED]

    I am in the process of changing my dungeon generation in my game to object pooling for efficiency, but I have run into an issue. Seemingly randomly when creating a new Object Pool I get a NullReferenceException for my prefab. I continue to replay the scenario and as far as I can tell there isn't a universal cause to the issue, it seems to happen randomly. Below are all the relevant functions with some unnecessary code removed for readability:

    Code (CSharp):
    1.     public void ExtractObjectFromPool(GameObject poolPrefab, Vector3 position, Quaternion rotation)
    2.     {
    3.         if (poolPrefab == null)
    4.         {
    5.             Debug.LogError("POOL PREFAB NOT FOUND?");
    6.         }
    7.  
    8.         int poolKey = poolPrefab.GetInstanceID();
    9.  
    10.         if (!poolDictionary.ContainsKey(poolKey)) //If there are no queues of the poolPrefab
    11.         {
    12.             print("New Pool Created");
    13.             CreateNewPool(poolKey, poolPrefab, position, rotation);
    14.         }
    15.         else
    16.         {
    17.             //EXTRACT OBJECT
    18.             GameObject objectToExtract = poolDictionary[poolKey].Dequeue();
    19.  
    20.             objectToExtract.SetActive(true);
    21.             objectToExtract.transform.SetParent(_activeItemsParent);
    22.             objectToExtract.transform.position = position;
    23.             objectToExtract.transform.rotation = rotation;
    24.  
    25.             //RETURN THE EXTRACTED OBJECT TO THE BACK OF THE QUEUE
    26.             poolDictionary[poolKey].Enqueue(objectToExtract);
    27.         }
    28.     }
    This is called from my dungeon generator each time it needs to spawn an item. If there is no created pool with the items it creates a new one. I know that the issue is not caused by the dungeon generator as the LogError is not called until AFTER the CreateNewPool function is called.

    Code (CSharp):
    1.     void CreateNewPool(int poolKey, GameObject poolPrefab, Vector3 position, Quaternion rotation)
    2.     {
    3.         int poolSize;
    4.  
    5.         //CREATE NEW POOL
    6.         print("New " + poolPrefab + " pool created!");
    7.         poolDictionary.Add(poolKey, new Queue<GameObject>());
    8.  
    9.         poolSize = poolPrefab.GetComponent<PooledObject>().maxObjectsPerLevel;
    10.  
    11.         //FILL POOL
    12.         for (int i = 0; i < poolSize; i++)
    13.         {
    14.             GameObject addedObject = Instantiate(poolPrefab) as GameObject;
    15.  
    16.             poolDictionary[poolKey].Enqueue(addedObject);
    17.  
    18.             addedObject.transform.SetParent(_unactiveItemsParent);
    19.             addedObject.SetActive(false);
    20.         }
    21.  
    22.         ExtractObjectFromPool(poolPrefab, position, rotation);
    23.     }
    The issue seems to be when passing the game object prefab from the CreateNewPool function back to the ExtractObjectFromPool function. However, I am not quite sure what is causing the poolPrefab to become null in the process of creating the new pool, and why this issue only arises sometimes.

    Any help would be greatly appreciated thanks!
     
    Last edited: May 13, 2019
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    So, which line does null ref for you?

    By the way, you don't need to cast Instantiate result if its the same type as a parameter.
    Also, avoid doing:
    Code (CSharp):
    1. gameObject.transform.something
    2. gameObject.transform.something
    3. gameObject.transform.something
    Do instead (gameObject.transform is a native GetComponent<Transform> call):
    Code (CSharp):
    1. Transform trm = gameObject.transform;
    2. trm.doSomething;
    3. trm.doSomething;
    4. trm.doSomething;
    You can as well do:
    Code (CSharp):
    1. transform.SetPositionAndRotation(position, rotation); // if Unity's version is above 5.6 (I think?)
    Also, use debugger and step your methods, you might find out whats going on.
     
    Last edited: May 13, 2019
  3. JamieRoss95

    JamieRoss95

    Joined:
    Apr 5, 2016
    Posts:
    28
    Thanks for the tips! I will incorporate those for sure.

    The NullRef is called here, in the ExtractObjectFromPool function:
    Code (CSharp):
    1. int poolKey = poolPrefab.GetInstanceID();
     
  4. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,296
    Are you sure you're calling ExtractObjectFromPool from the CreateNewPool method?

    Because if its null at the start, it would've thrown a null ref at:
    Code (CSharp):
    1. poolSize = poolPrefab.GetComponent<PooledObject>().maxObjectsPerLevel;
    in the CreateNewPool.
    Check the stack, it may point to somewhere else.
     
  5. JamieRoss95

    JamieRoss95

    Joined:
    Apr 5, 2016
    Posts:
    28
    That is the problem I have with figuring this out. CreateNewPool is called from ExtractObjectFromPool on the first pass through with a new prefab. Using DebugLogs I have confirmed that at no point during CreateNewPool is the poolPrefab null. However, at the start of ExtractObjectFromPool when the poolPrefab is passed back (at the end of the CreateNewPool function) it seems to be null for some reason.

    The even stranger part of the issue is that this NullRef seems to only happen about 1/5 times or so.

    EDIT: Solved. It was actually an issue with my DungeonGenerator script. Not sure why the DebugLog wasn't properly firing when it was passed Null the first time but the issue has been solved.

    Thanks for the help @xVergilx
     
    Last edited: May 13, 2019
    xVergilx likes this.