Search Unity

Help me finish my Objects_Pool script (SOLVED)

Discussion in 'Scripting' started by simonrauter, Jul 8, 2015.

  1. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    Hi! Im new to all of this and probably it will be a stupid question. I creates a scipt for object pooling (Unity tutorial http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/object-pooling). It is working great but it is only for one object so if I want to pool 3 different objects I need to make 3 scripts. I would really like to have all objects in one script. I tried to figure it out reading other posts here on forum but I just can't make it work... Like I said... I'm a noob =/

    I just need help with the last part marker in #region FROM HERE ON I NEED HELP

    Any help is appreciated! Thanks!

    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. [AddComponentMenu("Gameplay/Objects_Pool")]
    6. public class Objects_Pool : MonoBehaviour
    7. {
    8.     public static Objects_Pool objectsPool {get; private set;}
    9.  
    10.     [System.Serializable]
    11.     public class Objects_Pool_Entry
    12.     {
    13.         public GameObject pooledObject;
    14.         public int pooledAmount;
    15.         public bool expandPoolAmount;
    16.     }
    17.     public Objects_Pool_Entry[] entries;
    18.     List<GameObject>[] pooledObjects;
    19.  
    20.     void Awake ()
    21.     {
    22.         objectsPool = this;
    23.     }
    24.  
    25.     void Start ()
    26.     {
    27.         pooledObjects = new List<GameObject>[entries.Length];
    28.  
    29.         for (int i = 0; i < entries.Length; i++)
    30.         {
    31.             var objectpooledObject = entries[i];
    32.             pooledObjects[i] = new List<GameObject>();
    33.             for (int n = 0; n < objectpooledObject.pooledAmount; n++)
    34.             {
    35.                 var gameObject = Instantiate(objectpooledObject.pooledObject) as GameObject;
    36.                 gameObject.name = objectpooledObject.pooledObject.name;
    37.                 PoolObject(gameObject);
    38.             }
    39.         }
    40.     }
    41.  
    42.     public void PoolObject (GameObject newGameObject)
    43.     {
    44.         for (int i = 0; i < entries.Length; i++)
    45.         {
    46.             if (entries[i].pooledObject.name != newGameObject.name)
    47.                 continue;
    48.             newGameObject.SetActive(false);
    49.             pooledObjects[i].Add(newGameObject);
    50.         }
    51.     }
    52.  
    53.  
    54.  
    55. #region FROM HERE ON I NEED HELP
    56. // This is the code from original script.
    57. // I would like to change it for my new script that can accept more than one object.
    58.     public GameObject GetPooledObjects()
    59.     {
    60.         for(int i = 0; i < pooledObjects.Count; i++)
    61.         {
    62.             if(!pooledObjects[i].activeInHierarchy)
    63.             {
    64.                 return pooledObjects[i];
    65.             }
    66.         }
    67.            if(expandPoolAmount)
    68.         {
    69.             GameObject gameObject = (GameObject)Instantiate(pooledObject);
    70.             gameObject.name = pooledObject.name;
    71.             pooledObjects.Add (gameObject);
    72.             return gameObject;
    73.         }
    74.         return null;
    75.     }
    76. }
    77. #endregion
     
    Last edited: Jul 9, 2015
  2. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    Keep the pooling script from the tutorial as is.

    You can then create 3 game objects with the pooling script and assign the wanted value (prefab, count, etc.)
    Or
    You could create a script that will create the 3 game objects for you and assign them the pooling script.
     
  3. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    Almost figured it out... Just need help with last part marked in #region FROM HERE ON I NEED HELP

    Any help is appreciated! Thanks!
     
  4. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    When calling GetPooledObjects, do you want to get the first object that is inactive careless of which object it is?

    If so, it's just a matter of looping through both of your collections (your array and then your list) like so:
    Code (csharp):
    1. public GameObject GetPooledObjects()
    2. {
    3.     for(int i = 0; i < pooledObjects.Length; i++)
    4.     {
    5.         for(int j = 0; j < pooledObjects[i].Count; j++)
    6.         {
    7.             if(!pooledObjects[i][j].activeInHierarchy)
    8.                 return pooledObjects[i][j];
    9.         }
    10.     }
    11.    return null;
    12. }

    But did you you want to get one of each?
    Loop through all array and then return the first not active object in the hierarchy of each List?

    Or do you want to get one randomly?
    You could randomly select an index of your array and then loop in that List, kinda like this?


    Code (csharp):
    1. public GameObject GetRandomPooledObjects()
    2. {
    3.  
    4.     int randomIndex = Random.Range(0, pooledObjects.Length);
    5.  
    6.     for(int j = 0; j < pooledObjects[randomIndex].Count; j++)
    7.     {
    8.         if(!pooledObjects[randomIndex][j].activeInHierarchy)
    9.             return pooledObjects[randomIndex][j];
    10.     }
    11.  
    12.     return null;
    13. }


    But most of all, your initial code can be much simplified, I would do something like this..
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class MultipleObjectsPooling : MonoBehaviour
    6. {
    7.     [System.Serializable]
    8.     public class Objects_Pool_Entry
    9.     {
    10.         public GameObject pooledObject;
    11.         public int pooledAmount;
    12.         public bool expandPoolAmount;
    13.     }
    14.     public Objects_Pool_Entry[] pooledEntries;
    15.     public List<GameObject> pooledObject;
    16.  
    17.     void Start ()
    18.     {
    19.         foreach(Objects_Pool_Entry entry in pooledEntries)
    20.         {
    21.             for(int i = 0; i < entry.pooledAmount; i++)
    22.             {
    23.                 var go = Instantiate(entry.pooledObject) as GameObject;
    24.                 go.name = entry.pooledObject.name;
    25.                 pooledObject.Add(go);
    26.                 go.SetActive(false);
    27.             }
    28.         }
    29.     }
    30.  
    31.     public GameObject GetPooledObjects()
    32.     {
    33.         foreach(GameObject go in pooledObject)
    34.         {
    35.             if(!go.activeInHierarchy)
    36.                 return go;
    37.         }
    38.         return null;
    39.     }
    40. }[CODE][/SPOILER]
     
  5. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    Really appreciate that you are trying to help me!!!

    Maybe I didn't explain it well... What I'm trying to achieve is: I will have 3 spaceships each shooting different type of bullets (lets say lazer, plasma, rockets). I'm trying to make my script so I can store all different type of bullets in one pool and with each spaceship only call one type of bullets.

    I figured out I need GetObjectForType and I almost did everything... Right now my script at start creates pool of bullets (lets say 10 of each). Spaceship only fires bullets that I want. If spaceship needs more than 10 bullets at the time it creates new ones. Only problem is when my bullets gets deactivated my script never checks if there are any deactivated bullets of that type in hierarchy that my ship could reuse and instead just keeps making new bullets all the time. Im trying to achieve that my script would first check if there are any bullets it can reuse before creating new ones.

    THIS IS PART OF MY SCRIPT
    Code (csharp):
    1. public GameObject GetObjectForType(string objectType)
    2.     {
    3.         for (int i = 0; i < entries.Length; i++)
    4.         {
    5.             var newPooledObject = entries[i].pooledObject;
    6.             if (newPooledObject.name != objectType)
    7.                 continue;
    8.             if (pooledObjects[i].Count > 0)
    9.             {            
    10.                 GameObject newestPooledObject = pooledObjects[i][0];
    11.                 pooledObjects[i].RemoveAt(0);
    12.                 newestPooledObject.SetActive(true);
    13.                 return newestPooledObject;
    14.             }
    15.             if (expandPoolAmount)
    16.             {
    17.                 GameObject newestGameObject = Instantiate(entries[i].pooledObject) as GameObject;
    18.                 newestGameObject.name = entries[i].pooledObject.name;
    19.                 return newestGameObject;
    20.             }
    21.         }
    22.         return null;
    23.     }
    24.  
    AND THIS IS THE PART THAT I CAN'T FIGURE OUT
    This is part from original script (supports only one type of bullets) that I'm trying to modify for more than one type of bullets.
    Code (csharp):
    1. if(!pooledObjects[i].activeInHierarchy)
    2.             {
    3.                 return pooledObjects[i];
    4.             }
    5.  
     
  6. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    Oh ok, I understand better now.

    The reason what you are trying to accomplish is not working is because you are exiting the function as soon as you found an object. Well anyway, if this was not an issue yet, it would of been eventually.

    Anyhow, I took my Optimized Solution (a few post above) and made it so it suits your needs.

    The method GetPooledObjects takes a bool parameter to determine if they should be auto activated or not.
    By default it's set to true.. so just calling the method will automatically setActive the next inactive objects.


    EDIT: Added the list expansion.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5.  
    6. public class MultipleObjectsPooling : MonoBehaviour
    7. {
    8.     [System.Serializable]
    9.     public class Objects_Pool_Entry
    10.     {
    11.         public GameObject pooledObject;
    12.         public int pooledAmount = 1;
    13.     }
    14.     public Objects_Pool_Entry[] pooledEntries;
    15.     public bool expandPoolAmount = true;
    16.  
    17.     List<GameObject>[] pooledObject;
    18.  
    19.     void Start ()
    20.     {
    21.         pooledObject = new List<GameObject>[pooledEntries.Length];
    22.  
    23.         for(int i = 0; i < pooledEntries.Length; i++)
    24.         {
    25.             pooledObject[i] = new List<GameObject>();
    26.  
    27.             for(int j = 0; j < pooledEntries[i].pooledAmount; j++)
    28.             {
    29.                 GameObject go = InstantiatePrefab(i);
    30.             }
    31.         }
    32.     }
    33.  
    34.     GameObject InstantiatePrefab(int arrayIndex, bool autoActivate = false)
    35.     {
    36.         var go = Instantiate(pooledEntries[arrayIndex].pooledObject) as GameObject;
    37.         go.name = pooledEntries[arrayIndex].pooledObject.name;
    38.         pooledObject[arrayIndex].Add(go);
    39.         go.SetActive(autoActivate);
    40.  
    41.         return go;
    42.     }
    43.  
    44.     public GameObject[] GetPooledObjects(bool autoActivate = true)
    45.     {
    46.         GameObject[] tempArray = new GameObject[pooledObject.Length];
    47.  
    48.         for(int i = 0; i < pooledObject.Length; i++)
    49.         {
    50.             for(int j = 0; j < pooledObject[i].Count; j++)
    51.             {
    52.                 if(!pooledObject[i][j].activeInHierarchy)
    53.                 {
    54.                     tempArray[i] = pooledObject[i][j];
    55.  
    56.                     if(autoActivate)
    57.                         pooledObject[i][j].SetActive(true);
    58.  
    59.                     break;
    60.                 }
    61.  
    62.                 if(j >= (pooledObject[i].Count - 1))
    63.                 {
    64.                     if(expandPoolAmount)
    65.                     {
    66.                         GameObject go = InstantiatePrefab(i);
    67.                     }
    68.                 }
    69.             }
    70.         }
    71.         return tempArray;
    72.     }
    73. }
    74.  
     
    Last edited: Jul 10, 2015
  7. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    With your help I MADE IT :)

    Almost gave up on this but when I saw that someone (you) is actually willing to help me out I stick to it. It took me 5 days (12+ hours/day) to make it work. It's a hard life if you are noob like me hehe.

    Well I made my script to work exactly how I wanted. Still didn't figure out your optimized version. Don't know how to call the object from your script to even try it out... But your example did make me understand what I'm doing wrong and how to make it work.

    Will give another try at your optimized version later when I learn a bit more about scripting hehe.

    THANK YOU AGAIN SLUICE!!!

    This is my final version
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class Objects_Pool : MonoBehaviour
    6. {
    7.     public static Objects_Pool objectsPool;
    8.  
    9.     [System.Serializable]
    10.     public class Objects_Pool_Entry
    11.     {
    12.         public GameObject pooledObject;
    13.         public int pooledAmount;
    14.     }
    15.     public bool expandPoolAmount = true;
    16.     public Objects_Pool_Entry[] entries;
    17.     public List<GameObject>[] pooledObjects;
    18.  
    19.     void OnEnable ()
    20.     {
    21.         objectsPool = this;
    22.     }
    23.  
    24.     void Start ()
    25.     {
    26.         pooledObjects = new List<GameObject>[entries.Length];
    27.  
    28.         for (int i = 0; i < entries.Length; i++)
    29.         {
    30.             var objectpooledObject = entries[i];
    31.             pooledObjects[i] = new List<GameObject>();
    32.             for (int n = 0; n < objectpooledObject.pooledAmount; n++)
    33.             {
    34.                 var gameObject = Instantiate(objectpooledObject.pooledObject) as GameObject;
    35.                 gameObject.name = objectpooledObject.pooledObject.name;
    36.                 PoolObject(gameObject);
    37.             }
    38.         }
    39.     }
    40.  
    41.     public void PoolObject (GameObject newGameObject)
    42.     {
    43.         for (int i = 0; i < entries.Length; i++)
    44.         {
    45.             if (entries[i].pooledObject.name != newGameObject.name)
    46.                 continue;
    47.             newGameObject.SetActive(false);
    48.             pooledObjects[i].Add(newGameObject);
    49.         }
    50.     }
    51.  
    52.     public GameObject GetObjectForType(string objectType)
    53.     {
    54.         for (int i = 0; i < entries.Length; i++)
    55.         {
    56.             var newPooledObject = entries[i].pooledObject;
    57.             if (newPooledObject.name != objectType)
    58.                 continue;
    59.             for (int n = 0; n <pooledObjects[i].Count; n++)
    60.             {
    61.                 if(!pooledObjects[i][n].activeInHierarchy)
    62.                 {
    63.                     return pooledObjects[i][n];
    64.                 }
    65.             }
    66.             if (expandPoolAmount)
    67.             {
    68.                 GameObject newestgameObject = Instantiate(entries[i].pooledObject) as GameObject;
    69.                 newestgameObject.name = entries[i].pooledObject.name;
    70.                 pooledObjects[i].Add(newestgameObject);
    71.             }
    72.         }
    73.         return null;
    74.     }
    75. }
     
  8. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    Congrats! We are all Noobs at some point! So don't worry about it. :D

    Here is a package containing the complete project, it could always of be of help:
    http://www.sluicegaming.com/shared/MultipleObjectsPoolingProject.unitypackage

    How to use the package:
    1. Create a new project (3D mode)
    2. Go to: Asset / Import Package / Custom Package...
    3. Select the download package from my link.
    4. Import everything
    5. Open the scene name Test
    6. Test out the scene.. (Left mouse press will trigger the GetPoolObject)
    7. Look at your inspector to see the Instantiate objects being toggled. By default there are only 1 of each prefab to show that the expandPool works. Obviously, you would set a few more normally...



     
  9. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    Testing now... Only thing that is not for me is that when I pressed mouse button all 3 of them were activated at same time and I only want lets say circle. I need to be able to pool only 1 object from all different objects that are pooled at start.
     
  10. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    Oh wait, I think we misunderstood ourselves (again), lol.

    You have 3 spaceships.
    They each shoot a different projectile?

    Therefore, it's even easier and you could of avoided all that trouble and only use the regular Pooling script (from the Live Archives).

    Question: How do they shoot? Is it at the same time? (you press fire and the 3 spaceships shoot?)
     
  11. sluice

    sluice

    Joined:
    Jan 31, 2014
    Posts:
    416
    But either way, don't worry about it, if your solution works ;)
     
  12. simonrauter

    simonrauter

    Joined:
    Jun 19, 2015
    Posts:
    7
    I will have 1 player spaceship with 3 different weapon slots (one at front, one on left side, one on right side). When I press "Fire1" I want to shoot lazer bullet at front, when I press "Fire2" I want to shoot plazma on left side and when I press "Fire3" I want to shoot rocket on right side.

    And also all enemies in the game will use same pool for their bullets that is why I tried so hard to make one big pool work.

    Yea I made it work (just added one more line of code to fix spawn position when I move).
    if you wanna see how it works http://www.fibros.net/simon/demo.unitypackage

    So happy =) Thanks again for everything!
     
    Last edited: Jul 11, 2015