Search Unity

  1. Get the latest news, tutorials and offers directly to your inbox with our newsletters. Sign up now.
    Dismiss Notice

Prefab Pool System will grow if needed (inspector friendly)

Discussion in 'Scripting' started by Bunzaga, Feb 25, 2013.

  1. Bunzaga

    Bunzaga

    Joined:
    Jan 9, 2009
    Posts:
    195
    I am working on an Android project, and had to make a prefab pool system, so figured I would give this away to the public.

    Code (csharp):
    1.  
    2. #pragma strict
    3. import System.Collections.Generic;
    4. public class PrefabPool extends MonoBehaviour{
    5.     // stack location to put everything
    6.     public var stackLoc:Vector3 = Vector3(0, 99999, 0);
    7.     // array of prefabs queues for editor friendly
    8.     public var prefabs:PrefabQueue[];
    9.     // internal dictionary of queues for 'string' friendly
    10.     private var pRef:Dictionary.<String, PrefabQueue> = new Dictionary.<String, PrefabQueue>();
    11.     // static instance of self
    12.     public static var instance:PrefabPool;
    13.     // constructor
    14.     public function PrefabPool(){
    15.         instance = this;
    16.     }
    17.     // before any other functions...
    18.     public function Awake(){
    19.         for(var i:int = 0; i < prefabs.length; ++i){
    20.             pRef.Add(prefabs[i].prefab.name, prefabs[i]);
    21.             prefabs[i].Init();
    22.         }
    23.     }
    24.     // dequeue a prefab
    25.     public static function DequeuePrefab( _name:String ){
    26.         // if one is available, return it
    27.         if(instance.pRef[_name].queue.Count > 0){
    28.             var returnPrefab:Transform = instance.pRef[_name].queue.Dequeue();
    29.             returnPrefab.parent = null;
    30.             returnPrefab.gameObject.SetActiveRecursively(true);
    31.             #if UNITY_EDITOR
    32.             instance.pRef[_name].enqueued = instance.pRef[_name].queue.Count;
    33.             instance.pRef[_name].dequeued = instance.pRef[_name].count-instance.pRef[_name].enqueued;  
    34.             #endif
    35.             return returnPrefab;
    36.         }
    37.         // if one is not available, and we should grow, instantiate one
    38.         else{
    39.             if(true == instance.pRef[_name].growOnTheFly){
    40.                 returnPrefab = GameObject.Instantiate(instance.pRef[_name].prefab, instance.stackLoc, Quaternion.identity);
    41.                 returnPrefab.name = instance.pRef[_name].prefab.name;
    42.                 #if UNITY_EDITOR
    43.                 instance.pRef[_name].count ++;
    44.                 instance.pRef[_name].enqueued = instance.pRef[_name].queue.Count;
    45.                 instance.pRef[_name].dequeued = instance.pRef[_name].count-instance.pRef[_name].enqueued;
    46.                 #endif
    47.                 return returnPrefab;
    48.             }
    49.             else{
    50.                 // if one is not available, and we are not growing, reutrn null
    51.                 return null;
    52.             }
    53.         }
    54.     }
    55.     // requeue the old prefab when you're done with it
    56.     public static function EnqueuePrefab( _prefab:Transform ){
    57.         _prefab.gameObject.SetActiveRecursively(false);
    58.         _prefab.position = instance.stackLoc;
    59.         _prefab.parent = instance.gameObject.transform;
    60.         instance.pRef[_prefab.name].queue.Enqueue(_prefab);
    61.         #if UNITY_EDITOR
    62.         instance.pRef[_prefab.name].enqueued = instance.pRef[_prefab.name].queue.Count;
    63.         instance.pRef[_prefab.name].dequeued = instance.pRef[_prefab.name].count-instance.pRef[_prefab.name].enqueued;
    64.         #endif
    65.     }
    66.    
    67.     private class PrefabQueue{
    68.         // prefab type
    69.         public var prefab:Transform;
    70.         // max amount to make
    71.         public var maxCount:int;
    72.         // should we instantiate more prefbs if needed?
    73.         public var growOnTheFly:boolean = true;
    74.         #if UNITY_EDITOR
    75.         public var count:int = 0;
    76.         public var dequeued:int = 0;
    77.         public var enqueued:int = count;
    78.         #endif
    79.         // queue of prefabs
    80.         public var queue:Queue.<Transform> = new Queue.<Transform>();
    81.         // create new prefabs at the start of the game
    82.         public function Init(){
    83.             var i:int = maxCount;
    84.             while (i--){
    85.                 var newPrefab:Transform = GameObject.Instantiate(prefab, instance.stackLoc, Quaternion.identity);
    86.                 newPrefab.gameObject.SetActiveRecursively(false);
    87.                 newPrefab.name = prefab.name;
    88.                 newPrefab.parent = instance.gameObject.transform;
    89.                 queue.Enqueue(newPrefab);
    90.             }
    91.             #if UNITY_EDITOR
    92.             dequeued = 0;
    93.             enqueued = maxCount;
    94.             count = maxCount;
    95.             #endif
    96.         }
    97.     }
    98. }
    99.  
    What I like about this, is you can drag and drop variables inside the editor, but it uses a dictionary at runtime.

    To use it, drag it to an empty game object in the scene. You can set the off screen stack position, and then set the size of the Prefabs array to gain access to individual prefab pool settings.

    Prefab: the prefab to pool.
    Max Count: the default amount to spawn at the start.
    Grow On The Fly: should the pool instantiate new prefabs if none are available?

    Count, Enqueued and Dequeued are inspector only variables, so you can see what happens when you use the pool system. At build time, these variables aren't even created or used.

    To get a pooled instance, you drag the script to an empty game object ( I usually put mine at 0,0,0 ). Then instead of using Instantiate... You use PrefabPool.Dequeue( prefabStringName );

    When you are done with the prefab, and want to re-add it to the pool, you use PrefabPool.Enqueue( prefab );

    I was thinking of adding a pool decay system, where instances would delete after they haven't been used for a certain amount of time, but I wanted this to be light weight, and generic, so feel free to add that if you want it yourself. :D

    Let me know if there are any questions, or suggestions.

    Bunzaga
     
unityunity