Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Voting for the Unity Awards are OPEN! We’re looking to celebrate creators across games, industry, film, and many more categories. Cast your vote now for all categories
    Dismiss Notice
  3. Dismiss Notice

Spawn, despawn...then respawn in the wrong position (Mods please delete)

Discussion in 'Scripting' started by benvanj, Aug 13, 2018.

  1. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    I have a script that helps me with my pooler, which is fantastic but I have problems with the spawning.

    The script goes like this:
    Code (CSharp):
    1. {
    2.  
    3.     public GameObject spawnPrefab;
    4.     public bool randomChild;
    5.     public int addToPool;
    6.     public int minPool;
    7.     public float spawnInterval;
    8.     public float spawnVelocity;
    9.     public float spawnAngleError;
    10.  
    11.    public Transform ItemGenPoint;
    12.  
    13.     float nextSpawn;
    14.     Rigidbody myRigidbody;
    15.  
    16.     void Awake ()
    17.     {
    18.         myRigidbody = gameObject.GetComponent<Rigidbody>();
    19.         MF_AutoPool.InitializeSpawn( spawnPrefab, addToPool, minPool );
    20.     }
    21.  
    22.     void Update ()
    23.     {
    24.         if ( Time.time >= nextSpawn )
    25.         {
    26.  
    27.             Vector2 errorV2 = Random.insideUnitCircle * spawnAngleError;
    28.             Quaternion spawnAngle = Quaternion.Euler( errorV2.x, errorV2.y, 0 );
    29.  
    30.             GameObject obj = null;
    31.             if ( randomChild == true )
    32.             {
    33.                 obj = MF_AutoPool.Spawn(spawnPrefab, Random.Range(0, 3), ItemGenPoint.transform.position, transform.rotation * spawnAngle);
    34.             } else
    35.             {
    36.                 obj = MF_AutoPool.Spawn( spawnPrefab, ItemGenPoint.transform.position + (spawnAngle * transform.forward), transform.rotation * spawnAngle );
    37.             }
    38.  
    39.             // add some force and some random direction
    40.             Rigidbody rb = null;
    41.             if ( obj )
    42.             {
    43.                 rb = obj.GetComponent<Rigidbody>();
    44.             }
    45.             if ( rb )
    46.             {
    47.                 Vector3 myVelocity = myRigidbody ? myRigidbody.velocity : Vector3.zero;
    48.                 rb.velocity = myVelocity + ( obj.transform.forward * spawnVelocity );
    49.             }
    50.  
    51.             nextSpawn = Time.time + spawnInterval;
    52.         }
    53.     }
    54. }
    Int the text above: line 11 .... I added in to help me spawn the object in the right place... but when it despawns and respawns it, respawns in the original position and not in the new position...

    Please help...
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    So is that the object pooler class? Is
    randomChild
    true or false? Can you show the code for both versions of
    MF_AutoPool.Spawn
    .
     
  3. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Random child is true... I need it as my prefab is a gameObject (parent) with 3 Children... while Random child is true is Randomly spawns between the 3 children...

    The code for AutoPool...:
    Code (CSharp):
    1.  
    2.  
    3.     public PoolBlock poolBlock;
    4.  
    5.     [HideInInspector] public Stack<PoolItem> pool;
    6.     [HideInInspector] public List<PoolItem> masterPool; // only used when using EmptyBehavior.ReuseOldest
    7.  
    8.     int addedObjects;
    9.     int failedSpawns;
    10.     int reusedObjects;
    11.     int peakObjects;
    12.     int origSize;
    13.     int initSize;
    14.     int dynamicSize;
    15.     bool loaded;
    16.  
    17.     [System.Serializable]
    18.     public class PoolBlock {
    19.         [Tooltip("Initial number of object in the pool.")]
    20.         public int size = 32;
    21.         [Tooltip("Behavior when an object is requested and the pool is empty.\n\n" +
    22.             "Grow - Will add a new object to the pool, \nlimited by Max Size.\n\n" +
    23.             "Fail - No object will be spawned.\n\n" +
    24.             "Reuse Oldest - Will reuse the oldest active object." )] // becomes slower than grow for large pools, but faster with small pools
    25.         public AP_enum.EmptyBehavior emptyBehavior;
    26.         [Tooltip("When using Grow behaviour, this is the absolute max size the pool can grow to.")]
    27.         public int maxSize = 64; // absolut limit on pool size, used with EmptyBehavior Grow mode
    28.         [Tooltip("Behavior when an object is requested and the pool is empty, and the max size of the pool has been reached.\n\n" +
    29.             "Fail - No object will be spawned.\n\n" +
    30.             "Reuse Oldest - Will reuse the oldest active object.")]
    31.         public AP_enum.MaxEmptyBehavior maxEmptyBehavior; // mode when pool is at the max size
    32.         [Tooltip("Object that this pool contains.")]
    33.         public GameObject prefab;
    34.         [Tooltip("When the scene is stopped, creates a report showing pool usage:\n\n" +
    35.             "Start Size - Size of the pool when the scene started.\n\n" +
    36.             "End Size - Size of the pool when the scene ended.\n\n" +
    37.             "Added Objects - Number of objects added to the pool beyond the Start Size.\n\n" +
    38.             "Failed Spawns - Number of spawns failed due to no objects available in the pool.\n\n" +
    39.             "Reused Objects - Number of objects reused before they were added back to the pool.\n\n" +
    40.             "Most Objects Active - The most pool objects ever active at the same time.")]
    41.         public bool printLogOnQuit;
    42.  
    43.         public PoolBlock ( int size, AP_enum.EmptyBehavior emptyBehavior, int maxSize, AP_enum.MaxEmptyBehavior maxEmptyBehavior, GameObject prefab, bool printLogOnQuit ) {
    44.             this.size = size;
    45.             this.emptyBehavior = emptyBehavior;
    46.             this.maxSize = maxSize;
    47.             this.maxEmptyBehavior = maxEmptyBehavior;
    48.             this.prefab = prefab;
    49.             this.printLogOnQuit = printLogOnQuit;
    50.         }
    51.     }
    52.  
    53.     [System.Serializable]
    54.     public class PoolItem {
    55.         public GameObject obj;
    56.         public AP_Reference refScript;
    57.  
    58.         public PoolItem ( GameObject obj, AP_Reference refScript ) {
    59.             this.obj = obj;
    60.             this.refScript = refScript;
    61.         }
    62.     }
    63.  
    64.     void OnValidate () {
    65.         if ( loaded == false ) { // only run during editor
    66.             if ( poolBlock.maxSize <= poolBlock.size ) { poolBlock.maxSize = poolBlock.size * 2; }
    67.         }
    68.     }
    69.  
    70.     void Awake () {
    71.         loaded = true;
    72.  
    73.         // required to allow creation or modification of pools at runtime. (Timing of script creation and initialization can get wonkey)
    74.         if ( poolBlock == null ) {
    75.             poolBlock = new PoolBlock( 0, AP_enum.EmptyBehavior.Grow, 0, AP_enum.MaxEmptyBehavior.Fail, null, false );
    76.         } else {
    77.             poolBlock = new PoolBlock( poolBlock.size, poolBlock.emptyBehavior, poolBlock.maxSize, poolBlock.maxEmptyBehavior, poolBlock.prefab, poolBlock.printLogOnQuit );
    78.         }
    79.         pool = new Stack<PoolItem>();
    80.         masterPool = new List<PoolItem>();
    81.  
    82.         origSize = Mathf.Max( 0, poolBlock.size);
    83.         poolBlock.size = 0;
    84.  
    85.         for ( int i=0; i < origSize; i++ ) {
    86.             CreateObject( true );
    87.         }
    88.     }
    89.  
    90.     void Start () {
    91.         Invoke( "StatInit", 0 ); // for logging after dynamic creation of pool objects from other scripts
    92.     }
    93.  
    94.     void StatInit () { // for logging after dynamic creation of pool objects from other scripts
    95.         initSize = poolBlock.size - origSize;
    96.     }
    97.        
    98.     public GameObject Spawn () { // use to call spawn directly from the pool, and also used by the "Spawn" button in the editor
    99.         return Spawn( null, Vector3.zero, Quaternion.identity, false );
    100.     }
    101.     public GameObject Spawn ( int? child ) { // use to call spawn directly from the pool
    102.         return Spawn( child, Vector3.zero, Quaternion.identity, false );
    103.     }
    104.     public GameObject Spawn ( Vector3 pos, Quaternion rot ) { // use to call spawn directly from the pool
    105.         return Spawn( null, pos, rot, true );
    106.     }
    107.     public GameObject Spawn ( int? child, Vector3 pos, Quaternion rot ) { // use to call spawn directly from the pool
    108.         return Spawn( child, pos, rot, true );
    109.     }
    110.     public GameObject Spawn ( int? child, Vector3 pos, Quaternion rot, bool usePosRot ) {
    111.         GameObject obj = GetObject();
    112.         if ( obj == null ) { return null; } // early out
    113.  
    114.         obj.SetActive(false); // reset item in case object is being reused, has no effect if object is already disabled
    115.         obj.transform.parent = null;
    116.         obj.transform.position = usePosRot ? pos : transform.position;
    117.         obj.transform.rotation = usePosRot ? rot : transform.rotation;
    118.    
    119.         obj.SetActive(true);
    120.  
    121.         if ( child != null && child < obj.transform.childCount ) { // activate a specific child
    122.             obj.transform.GetChild( (int)child ).gameObject.SetActive(true);
    123.         }
    124.  
    125.         if ( peakObjects < poolBlock.size - pool.Count ) { peakObjects = poolBlock.size - pool.Count; } // for logging
    126.         return obj;
    127.     }
    128.  
    129.     public void Despawn ( GameObject obj, AP_Reference oprScript ) { // return an object back to this pool
    130.         if ( obj.transform.parent == transform ) { return; } // already in pool
    131.         obj.SetActive(false);
    132.         obj.transform.parent = transform;
    133.         obj.transform.localPosition = Vector3.zero;
    134.         obj.transform.localRotation = Quaternion.identity;
    135.         oprScript.CancelInvoke();
    136.         pool.Push( new PoolItem( obj, oprScript ) );
    137.     }
    138.  
    139.     public GameObject GetObject () { // get object from pool, creating one if necessary and if settings allow
    140.         GameObject result = null;
    141.         if ( pool.Count == 0 ) {
    142.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.Fail ) { failedSpawns++; return null; }
    143.  
    144.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.ReuseOldest ) {
    145.                 result = FindOldest();
    146.                 if ( result != null ) { reusedObjects++; }
    147.             }
    148.  
    149.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.Grow ) {
    150.                 if ( poolBlock.size >= poolBlock.maxSize ) {
    151.                     if ( poolBlock.maxEmptyBehavior == AP_enum.MaxEmptyBehavior.Fail ) { failedSpawns++; return null; }
    152.                     if ( poolBlock.maxEmptyBehavior == AP_enum.MaxEmptyBehavior.ReuseOldest ) {
    153.                         result = FindOldest();
    154.                         if ( result != null ) { reusedObjects++; }
    155.                     }
    156.                 } else {
    157.                     addedObjects++;
    158.                     return CreateObject();
    159.                 }
    160.             }
    161.         } else {
    162.             pool.Peek().refScript.timeSpawned = Time.time;
    163.             return pool.Pop().obj;
    164.         }
    165.         return result;
    166.     }
    167.  
    168.     GameObject FindOldest () { // will also set timeSpawned for returned object
    169.         GameObject result = null;
    170.         int oldestIndex = 0;
    171.         float oldestTime = Mathf.Infinity;
    172.         if ( masterPool.Count > 0 ) {
    173.             for ( int i = 0; i < masterPool.Count; i++ ) {
    174.                 if ( masterPool[i] == null || masterPool[i].obj == null ) { continue; } // make sure object still exsists
    175.                 if ( masterPool[i].refScript.timeSpawned < oldestTime ) {
    176.                     oldestTime = masterPool[i].refScript.timeSpawned;
    177.                     result = masterPool[i].obj;
    178.                     oldestIndex = i;
    179.                 }
    180.             }
    181.             masterPool[ oldestIndex ].refScript.timeSpawned = Time.time;
    182.         }
    183.         return result;
    184.     }
    185.  
    186.     public GameObject CreateObject () {
    187.         return CreateObject ( false );
    188.     }
    189.     public GameObject CreateObject ( bool createInPool ) { // true when creating an item in the pool without spawing it
    190.         GameObject obj = null;
    191.         if ( poolBlock.prefab ) {
    192.             obj = (GameObject) Instantiate( poolBlock.prefab, transform.position, transform.rotation );
    193.             AP_Reference oprScript = obj.GetComponent<AP_Reference>();
    194.             if ( oprScript == null ) { oprScript = obj.AddComponent<AP_Reference>(); }
    195.             oprScript.poolScript = this;
    196.             oprScript.timeSpawned = Time.time;
    197.             masterPool.Add( new PoolItem( obj, oprScript ) );
    198.  
    199.             if ( createInPool == true ) {
    200.                 pool.Push( new PoolItem( obj, oprScript ) );
    201.                 obj.SetActive(false);
    202.                 obj.transform.parent = transform;
    203.             }
    204.             poolBlock.size++;
    205.         }
    206.         return obj;
    207.     }
    208.  
    209.     public int GetActiveCount () {
    210.         return poolBlock.size - pool.Count;
    211.     }
    212.  
    213.     public int GetAvailableCount () {
    214.         return pool.Count;
    215.     }
    216.  
    217.     void OnApplicationQuit () {
    218.         if ( poolBlock.printLogOnQuit == true ) {
    219.             PrintLog();
    220.         }
    221.     }
    222.  
    223.     public void PrintLog () {
    224.         Debug.Log( transform.name + ":       Start Size: " + origSize + "    Init Added: " + initSize + "    Grow Objects: " + addedObjects + "    End Size: " + poolBlock.size + "\n" +
    225.             "    Failed Spawns: " + failedSpawns + "    Reused Objects: " + reusedObjects + "     Most objects active at once: " + peakObjects );
    226.     }
    227.  
    228. }
     
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Is that the AutoPool class (the class name line is missing)? Is
    MF_AutoPool
    of type
    AutoPool
    ?

    That means it is calling this version of Spawn:
    obj = MF_AutoPool.Spawn(spawnPrefab, Random.Range(0, 3), ItemGenPoint
    I can't see a Spawn method taking an int as the second parameter?
     
  5. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    everything you said went straight over my head.... Let me post all the scripts:

    Pool Manager:
    Code (CSharp):
    1. public class AP_Manager : MonoBehaviour {
    2.  
    3.     public bool allowCreate = true;
    4.     public bool allowModify = true;
    5.  
    6.     [Tooltip("When the scene is stopped, creates a report showing pool usage:\n\n" +
    7.         "Start Size - Size of pool when beginning the scene.\n\n" +
    8.         "Init Added - Number of objects added by InitializeSpawn() at runtime.\n\n" +
    9.         "Grow Objects - Number of objects added with EmptyBehavior.Grow.\n\n" +
    10.         "End Size - Total objects of this pool, active and inactive, at the time of the log report.\n\n" +
    11.         "Failed Spawns - Number of Spawn() requests that didn't return a spawn.\n\n" +
    12.         "Reused Objects - Number of times an object was reused before despawning normally.\n\n" +
    13.         "Most Objects Active - The most items for this pool active at once.")]
    14.     public bool printAllLogsOnQuit;
    15.  
    16.     [HideInInspector] public Dictionary<GameObject, AP_Pool> poolRef;
    17.  
    18.     void Awake () {
    19.         CheckDict();
    20.     }
    21.  
    22.     void CheckDict() {
    23.         if ( poolRef == null ) { // dictionary hasn't been created yet
    24.             poolRef = new Dictionary<GameObject, AP_Pool>();
    25.         }
    26.     }
    27.  
    28.     public bool InitializeSpawn ( GameObject obj, float addPool, int minPool, AP_enum.EmptyBehavior emptyBehavior, AP_enum.MaxEmptyBehavior maxEmptyBehavior, bool modBehavior ) {
    29.         if ( obj == null ) { return false; }
    30.         CheckDict();
    31.         bool result = false;
    32.         bool tempModify = false;
    33.  
    34.         if ( poolRef.ContainsKey( obj ) == true && poolRef[obj] == null ) { // check for broken reference
    35.             poolRef.Remove( obj ); // remove it
    36.         }
    37.         if ( poolRef.ContainsKey( obj ) == true ) {
    38.                 result = true; // already have refrence
    39.         } else {
    40.             if ( MakePoolRef( obj ) == null ) { // ref not found
    41.                 if ( allowCreate == true ) {
    42.                     CreatePool( obj, 0, 0, emptyBehavior, maxEmptyBehavior );
    43.                     tempModify = true; // may modify a newly created pool
    44.                     result = true;
    45.                 } else {
    46.                     result = false;
    47.                 }
    48.             } else {
    49.                 result = true; // ref was created
    50.             }
    51.         }
    52.  
    53.         if ( result == true ) { // hava a valid pool ref
    54.             if ( allowModify == true || tempModify == true ) { // may modify a newly created pool
    55.                 if ( addPool > 0 || minPool > 0 ) {
    56.                     int size = poolRef[obj].poolBlock.size;
    57.                     int l1 = 0; int l2 = 0;
    58.                     if ( addPool >= 0 ) { // not negative
    59.                         if ( addPool < 1 ) { // is a percentage
    60.                             l2 = Mathf.RoundToInt( size * addPool );
    61.                         } else { // not a percentage
    62.                             l1 = Mathf.RoundToInt( addPool );
    63.                         }
    64.                     }
    65.                     int loop = 0;
    66.                     int a = size == 0 ? 0 : Mathf.Max( l1, l2 );
    67.                     if ( size < minPool ) { loop = minPool - size; }
    68.                     loop += a;
    69.                     for ( int i=0; i < loop; i++ ) {
    70.                         poolRef[obj].CreateObject( true );
    71.                     }
    72.                     poolRef[obj].poolBlock.maxSize = poolRef[obj].poolBlock.size * 2;
    73.                     if ( modBehavior == true ) {
    74.                         poolRef[obj].poolBlock.emptyBehavior = emptyBehavior;
    75.                         poolRef[obj].poolBlock.maxEmptyBehavior = maxEmptyBehavior;
    76.                     }
    77.                 }
    78.             }
    79.         }
    80.  
    81.         return result;
    82.     }
    83.  
    84.     public GameObject Spawn ( GameObject obj, int? child, Vector3 pos, Quaternion rot, bool usePosRot ) {
    85.         if ( obj == null ) { return null; } // object wasn't defined
    86.         CheckDict();
    87.  
    88.         if ( poolRef.ContainsKey( obj ) == true ) { // reference already created
    89.             if ( poolRef[obj] != null ) { // make sure pool still exsists
    90.                 return poolRef[obj].Spawn( child, pos, rot, usePosRot ); // create spawn
    91.             } else { // pool no longer exsists
    92.                 poolRef.Remove( obj ); // remove reference
    93.                 return null;
    94.             }
    95.         } else { // ref not yet created
    96.             AP_Pool childScript = MakePoolRef ( obj ); // create ref
    97.             if ( childScript == null ) { // ref not found
    98.                 return null;
    99.             } else {
    100.                 return childScript.Spawn( child, pos, rot, usePosRot ); // create spawn
    101.             }
    102.         }
    103.     }
    104.  
    105.     AP_Pool MakePoolRef ( GameObject obj ) { // attempt to create and return script reference
    106.         for ( int i=0; i < transform.childCount; i++ ) {
    107.             AP_Pool childScript = transform.GetChild(i).GetComponent<AP_Pool>();
    108.             if ( childScript && obj == childScript.poolBlock.prefab ) {
    109.                 poolRef.Add( obj, childScript );
    110.                 return childScript;
    111.             }
    112.         }
    113. //        Debug.Log( obj.name + ": Tried to reference object pool, but no matching pool was found." );
    114.         return null;
    115.     }
    116.  
    117.     public int GetActiveCount ( GameObject prefab ) {
    118.         if ( prefab == null ) { return 0; } // object wasn't defined
    119.         AP_Pool childScript = null;
    120.         if ( poolRef.ContainsKey( prefab ) == true ) { // reference already created
    121.             childScript = poolRef[prefab];
    122.         } else { // ref not yet created
    123.             childScript = MakePoolRef ( prefab ); // create ref
    124.         }
    125.         if ( childScript == null ) { // pool not found
    126.             return 0;
    127.         } else {
    128.             return childScript.poolBlock.size - childScript.pool.Count;
    129.         }
    130.     }
    131.  
    132.     public int GetAvailableCount ( GameObject prefab ) {
    133.         if ( prefab == null ) { return 0; } // object wasn't defined
    134.         AP_Pool childScript = null;
    135.         if ( poolRef.ContainsKey( prefab ) == true ) { // reference already created
    136.             childScript = poolRef[prefab];
    137.         } else { // ref not yet created
    138.             childScript = MakePoolRef ( prefab ); // create ref
    139.         }
    140.         if ( childScript == null ) { // pool not found
    141.             return 0;
    142.         } else {
    143.             return childScript.pool.Count;
    144.         }
    145.     }
    146.  
    147.     public bool RemoveAll () {
    148.         bool result = true;
    149.         GameObject[] tempObj = new GameObject[poolRef.Count];
    150.         int i = 0;
    151.         foreach ( GameObject obj in poolRef.Keys ) {
    152.             if ( poolRef[obj] != null ) {
    153.                 tempObj[i] = obj;
    154.                 i++;
    155.             }
    156.         }
    157.         for ( int t=0; t < tempObj.Length; t++ ) {
    158.             if ( tempObj[t] != null ) {
    159.                 if ( RemovePool( tempObj[t] ) == false ) { result = false; }
    160.             }
    161.         }
    162.         return result;
    163.     }
    164.  
    165.     public bool DespawnAll () {
    166.         bool result = true;
    167.         foreach ( GameObject obj in poolRef.Keys ) {
    168.             if ( DespawnPool( obj ) == false ) { result = false; }
    169.         }
    170.         return result;
    171.     }
    172.  
    173.     public bool RemovePool ( GameObject prefab ) {
    174.         if ( prefab == null ) { return false; } // object wasn't defined
    175.         bool result = false;
    176.         AP_Pool childScript = null;
    177.         if ( poolRef.ContainsKey( prefab ) == true ) { // reference already created
    178.             childScript = poolRef[prefab];
    179.         } else { // ref not yet created
    180.             childScript = MakePoolRef ( prefab ); // create ref
    181.         }
    182.         if ( childScript == null ) { // pool not found
    183.             return false;
    184.         } else {
    185.             result = DespawnPool( prefab );
    186.             Destroy( childScript.gameObject );
    187.             poolRef.Remove( prefab );
    188.             return result;
    189.         }
    190.     }
    191.        
    192.     public bool DespawnPool ( GameObject prefab ) {
    193.         if ( prefab == null ) { return false; } // object wasn't defined
    194.         AP_Pool childScript = null;
    195.         if ( poolRef.ContainsKey( prefab ) == true ) { // reference already created
    196.             childScript = poolRef[prefab];
    197.         } else { // ref not yet created
    198.             childScript = MakePoolRef ( prefab ); // create ref
    199.         }
    200.         if ( childScript == null ) { // pool not found
    201.             return false;
    202.         } else {
    203.             for ( int i=0; i < childScript.masterPool.Count; i++ ) {
    204.                 childScript.Despawn( childScript.masterPool[i].obj, childScript.masterPool[i].refScript ) ;
    205.             }
    206.             return true;
    207.         }
    208.     }
    209.  
    210.     public void CreatePool () {
    211.         CreatePool ( null, 32, 64, AP_enum.EmptyBehavior.Grow, AP_enum.MaxEmptyBehavior.Fail );
    212.     }
    213.     public void CreatePool ( GameObject prefab, int size, int maxSize, AP_enum.EmptyBehavior emptyBehavior, AP_enum.MaxEmptyBehavior maxEmptyBehavior ) {
    214.         GameObject obj = new GameObject("Object Pool");
    215.         obj.transform.parent = transform;
    216.         obj.transform.localPosition = Vector3.zero;
    217.         obj.transform.localRotation = Quaternion.identity;
    218.         AP_Pool script = obj.AddComponent<AP_Pool>();
    219.         if ( Application.isPlaying == true ) {
    220.             obj.name = prefab.name;
    221.             script.poolBlock.size = size;
    222.             script.poolBlock.maxSize = maxSize;
    223.             script.poolBlock.emptyBehavior = emptyBehavior;
    224.             script.poolBlock.maxEmptyBehavior = maxEmptyBehavior;
    225.             script.poolBlock.prefab = prefab;
    226.             if ( prefab ) { MakePoolRef( prefab ); }
    227.         }
    228.     }
    229.  
    230.     void OnApplicationQuit () {
    231.         if ( printAllLogsOnQuit == true ) {
    232.             PrintAllLogs();
    233.         }
    234.     }
    235.  
    236.     public void PrintAllLogs () {
    237.         foreach ( AP_Pool script in poolRef.Values ) {
    238.             script.PrintLog();
    239.         }
    240.     }
    241.  
    242. }
    Then I have to make pools as a child of the pool manager:

    The pooler script:

    Code (CSharp):
    1. public class AP_Pool : MonoBehaviour {
    2.  
    3.     public PoolBlock poolBlock;
    4.  
    5.     [HideInInspector] public Stack<PoolItem> pool;
    6.     [HideInInspector] public List<PoolItem> masterPool; // only used when using EmptyBehavior.ReuseOldest
    7.  
    8.     int addedObjects;
    9.     int failedSpawns;
    10.     int reusedObjects;
    11.     int peakObjects;
    12.     int origSize;
    13.     int initSize;
    14.     int dynamicSize;
    15.     bool loaded;
    16.  
    17.     [System.Serializable]
    18.     public class PoolBlock {
    19.         [Tooltip("Initial number of object in the pool.")]
    20.         public int size = 32;
    21.         [Tooltip("Behavior when an object is requested and the pool is empty.\n\n" +
    22.             "Grow - Will add a new object to the pool, \nlimited by Max Size.\n\n" +
    23.             "Fail - No object will be spawned.\n\n" +
    24.             "Reuse Oldest - Will reuse the oldest active object." )] // becomes slower than grow for large pools, but faster with small pools
    25.         public AP_enum.EmptyBehavior emptyBehavior;
    26.         [Tooltip("When using Grow behaviour, this is the absolute max size the pool can grow to.")]
    27.         public int maxSize = 64; // absolut limit on pool size, used with EmptyBehavior Grow mode
    28.         [Tooltip("Behavior when an object is requested and the pool is empty, and the max size of the pool has been reached.\n\n" +
    29.             "Fail - No object will be spawned.\n\n" +
    30.             "Reuse Oldest - Will reuse the oldest active object.")]
    31.         public AP_enum.MaxEmptyBehavior maxEmptyBehavior; // mode when pool is at the max size
    32.         [Tooltip("Object that this pool contains.")]
    33.         public GameObject prefab;
    34.         [Tooltip("When the scene is stopped, creates a report showing pool usage:\n\n" +
    35.             "Start Size - Size of the pool when the scene started.\n\n" +
    36.             "End Size - Size of the pool when the scene ended.\n\n" +
    37.             "Added Objects - Number of objects added to the pool beyond the Start Size.\n\n" +
    38.             "Failed Spawns - Number of spawns failed due to no objects available in the pool.\n\n" +
    39.             "Reused Objects - Number of objects reused before they were added back to the pool.\n\n" +
    40.             "Most Objects Active - The most pool objects ever active at the same time.")]
    41.         public bool printLogOnQuit;
    42.  
    43.         public PoolBlock ( int size, AP_enum.EmptyBehavior emptyBehavior, int maxSize, AP_enum.MaxEmptyBehavior maxEmptyBehavior, GameObject prefab, bool printLogOnQuit ) {
    44.             this.size = size;
    45.             this.emptyBehavior = emptyBehavior;
    46.             this.maxSize = maxSize;
    47.             this.maxEmptyBehavior = maxEmptyBehavior;
    48.             this.prefab = prefab;
    49.             this.printLogOnQuit = printLogOnQuit;
    50.         }
    51.     }
    52.  
    53.     [System.Serializable]
    54.     public class PoolItem {
    55.         public GameObject obj;
    56.         public AP_Reference refScript;
    57.  
    58.         public PoolItem ( GameObject obj, AP_Reference refScript ) {
    59.             this.obj = obj;
    60.             this.refScript = refScript;
    61.         }
    62.     }
    63.  
    64.     void OnValidate () {
    65.         if ( loaded == false ) { // only run during editor
    66.             if ( poolBlock.maxSize <= poolBlock.size ) { poolBlock.maxSize = poolBlock.size * 2; }
    67.         }
    68.     }
    69.  
    70.     void Awake () {
    71.         loaded = true;
    72.  
    73.         // required to allow creation or modification of pools at runtime. (Timing of script creation and initialization can get wonkey)
    74.         if ( poolBlock == null ) {
    75.             poolBlock = new PoolBlock( 0, AP_enum.EmptyBehavior.Grow, 0, AP_enum.MaxEmptyBehavior.Fail, null, false );
    76.         } else {
    77.             poolBlock = new PoolBlock( poolBlock.size, poolBlock.emptyBehavior, poolBlock.maxSize, poolBlock.maxEmptyBehavior, poolBlock.prefab, poolBlock.printLogOnQuit );
    78.         }
    79.         pool = new Stack<PoolItem>();
    80.         masterPool = new List<PoolItem>();
    81.  
    82.         origSize = Mathf.Max( 0, poolBlock.size);
    83.         poolBlock.size = 0;
    84.  
    85.         for ( int i=0; i < origSize; i++ ) {
    86.             CreateObject( true );
    87.         }
    88.     }
    89.  
    90.     void Start () {
    91.         Invoke( "StatInit", 0 ); // for logging after dynamic creation of pool objects from other scripts
    92.     }
    93.  
    94.     void StatInit () { // for logging after dynamic creation of pool objects from other scripts
    95.         initSize = poolBlock.size - origSize;
    96.     }
    97.        
    98.     public GameObject Spawn () { // use to call spawn directly from the pool, and also used by the "Spawn" button in the editor
    99.         return Spawn( null, Vector3.zero, Quaternion.identity, false );
    100.     }
    101.     public GameObject Spawn ( int? child ) { // use to call spawn directly from the pool
    102.         return Spawn( child, Vector3.zero, Quaternion.identity, false );
    103.     }
    104.     public GameObject Spawn ( Vector3 pos, Quaternion rot ) { // use to call spawn directly from the pool
    105.         return Spawn( null, pos, rot, true );
    106.     }
    107.     public GameObject Spawn ( int? child, Vector3 pos, Quaternion rot ) { // use to call spawn directly from the pool
    108.         return Spawn( child, pos, rot, true );
    109.     }
    110.     public GameObject Spawn ( int? child, Vector3 pos, Quaternion rot, bool usePosRot ) {
    111.         GameObject obj = GetObject();
    112.         if ( obj == null ) { return null; } // early out
    113.  
    114.         obj.SetActive(false); // reset item in case object is being reused, has no effect if object is already disabled
    115.         obj.transform.parent = null;
    116.         obj.transform.position = usePosRot ? pos : transform.position;
    117.         obj.transform.rotation = usePosRot ? rot : transform.rotation;
    118.    
    119.         obj.SetActive(true);
    120.  
    121.         if ( child != null && child < obj.transform.childCount ) { // activate a specific child
    122.             obj.transform.GetChild( (int)child ).gameObject.SetActive(true);
    123.         }
    124.  
    125.         if ( peakObjects < poolBlock.size - pool.Count ) { peakObjects = poolBlock.size - pool.Count; } // for logging
    126.         return obj;
    127.     }
    128.  
    129.     public void Despawn ( GameObject obj, AP_Reference oprScript ) { // return an object back to this pool
    130.         if ( obj.transform.parent == transform ) { return; } // already in pool
    131.         obj.SetActive(false);
    132.         obj.transform.parent = transform;
    133.         obj.transform.localPosition = Vector3.zero;
    134.         obj.transform.localRotation = Quaternion.identity;
    135.         oprScript.CancelInvoke();
    136.         pool.Push( new PoolItem( obj, oprScript ) );
    137.     }
    138.  
    139.     public GameObject GetObject () { // get object from pool, creating one if necessary and if settings allow
    140.         GameObject result = null;
    141.         if ( pool.Count == 0 ) {
    142.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.Fail ) { failedSpawns++; return null; }
    143.  
    144.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.ReuseOldest ) {
    145.                 result = FindOldest();
    146.                 if ( result != null ) { reusedObjects++; }
    147.             }
    148.  
    149.             if ( poolBlock.emptyBehavior == AP_enum.EmptyBehavior.Grow ) {
    150.                 if ( poolBlock.size >= poolBlock.maxSize ) {
    151.                     if ( poolBlock.maxEmptyBehavior == AP_enum.MaxEmptyBehavior.Fail ) { failedSpawns++; return null; }
    152.                     if ( poolBlock.maxEmptyBehavior == AP_enum.MaxEmptyBehavior.ReuseOldest ) {
    153.                         result = FindOldest();
    154.                         if ( result != null ) { reusedObjects++; }
    155.                     }
    156.                 } else {
    157.                     addedObjects++;
    158.                     return CreateObject();
    159.                 }
    160.             }
    161.         } else {
    162.             pool.Peek().refScript.timeSpawned = Time.time;
    163.             return pool.Pop().obj;
    164.         }
    165.         return result;
    166.     }
    167.  
    168.     GameObject FindOldest () { // will also set timeSpawned for returned object
    169.         GameObject result = null;
    170.         int oldestIndex = 0;
    171.         float oldestTime = Mathf.Infinity;
    172.         if ( masterPool.Count > 0 ) {
    173.             for ( int i = 0; i < masterPool.Count; i++ ) {
    174.                 if ( masterPool[i] == null || masterPool[i].obj == null ) { continue; } // make sure object still exsists
    175.                 if ( masterPool[i].refScript.timeSpawned < oldestTime ) {
    176.                     oldestTime = masterPool[i].refScript.timeSpawned;
    177.                     result = masterPool[i].obj;
    178.                     oldestIndex = i;
    179.                 }
    180.             }
    181.             masterPool[ oldestIndex ].refScript.timeSpawned = Time.time;
    182.         }
    183.         return result;
    184.     }
    185.  
    186.     public GameObject CreateObject () {
    187.         return CreateObject ( false );
    188.     }
    189.     public GameObject CreateObject ( bool createInPool ) { // true when creating an item in the pool without spawing it
    190.         GameObject obj = null;
    191.         if ( poolBlock.prefab ) {
    192.             obj = (GameObject) Instantiate( poolBlock.prefab, transform.position, transform.rotation );
    193.             AP_Reference oprScript = obj.GetComponent<AP_Reference>();
    194.             if ( oprScript == null ) { oprScript = obj.AddComponent<AP_Reference>(); }
    195.             oprScript.poolScript = this;
    196.             oprScript.timeSpawned = Time.time;
    197.             masterPool.Add( new PoolItem( obj, oprScript ) );
    198.  
    199.             if ( createInPool == true ) {
    200.                 pool.Push( new PoolItem( obj, oprScript ) );
    201.                 obj.SetActive(false);
    202.                 obj.transform.parent = transform;
    203.             }
    204.             poolBlock.size++;
    205.         }
    206.         return obj;
    207.     }
    208.  
    209.     public int GetActiveCount () {
    210.         return poolBlock.size - pool.Count;
    211.     }
    212.  
    213.     public int GetAvailableCount () {
    214.         return pool.Count;
    215.     }
    216.  
    217.     void OnApplicationQuit () {
    218.         if ( poolBlock.printLogOnQuit == true ) {
    219.             PrintLog();
    220.         }
    221.     }
    222.  
    223.     public void PrintLog () {
    224.         Debug.Log( transform.name + ":       Start Size: " + origSize + "    Init Added: " + initSize + "    Grow Objects: " + addedObjects + "    End Size: " + poolBlock.size + "\n" +
    225.             "    Failed Spawns: " + failedSpawns + "    Reused Objects: " + reusedObjects + "     Most objects active at once: " + peakObjects );
    226.     }
    227.  
    228. }
    Then I use a Spawner script to spawn:

    Code (CSharp):
    1. public class AP_DemoSpawn : MonoBehaviour {
    2.  
    3.     public GameObject spawnPrefab;
    4.     public bool randomChild;
    5.     public int addToPool;
    6.     public int minPool;
    7.     public float spawnInterval;
    8.     public float spawnVelocity;
    9.     public float spawnAngleError;
    10.  
    11.     public Transform ItemGenPoint;
    12.  
    13.     float nextSpawn;
    14.     Rigidbody myRigidbody;
    15.  
    16.     void Awake ()
    17.     {
    18.         myRigidbody = gameObject.GetComponent<Rigidbody>();
    19.         MF_AutoPool.InitializeSpawn( spawnPrefab, addToPool, minPool );
    20.     }
    21.  
    22.     void Update ()
    23.     {
    24.         if ( Time.time >= nextSpawn )
    25.         {
    26.  
    27.             Vector2 errorV2 = Random.insideUnitCircle * spawnAngleError;
    28.             Quaternion spawnAngle = Quaternion.Euler( errorV2.x, errorV2.y, 0 );
    29.  
    30.             GameObject obj = null;
    31.             if ( randomChild == true )
    32.             {
    33.                 obj = MF_AutoPool.Spawn(spawnPrefab, Random.Range(0, 3), ItemGenPoint.transform.position, transform.rotation * spawnAngle);
    34.             } else
    35.             {
    36.                 obj = MF_AutoPool.Spawn( spawnPrefab, ItemGenPoint.transform.position + (spawnAngle * transform.forward), transform.rotation * spawnAngle );
    37.             }
    38.  
    39.             // add some force and some random direction
    40.             Rigidbody rb = null;
    41.             if ( obj )
    42.             {
    43.                 rb = obj.GetComponent<Rigidbody>();
    44.             }
    45.             if ( rb )
    46.             {
    47.                 Vector3 myVelocity = myRigidbody ? myRigidbody.velocity : Vector3.zero;
    48.                 rb.velocity = myVelocity + ( obj.transform.forward * spawnVelocity );
    49.             }
    50.  
    51.             nextSpawn = Time.time + spawnInterval;
    52.         }
    53.     }
    54. }
     
  6. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    What is
    MF_AutoPool
    ? I don't see it declared anywhere in this code.
     
  7. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Here is the script for it:

    Code (CSharp):
    1. public class MF_AutoPool {
    2.  
    3.     static AP_Manager opmScript;
    4.  
    5.     // may be be called early and won't create a spawn, but will create a pool reference and return true if the reference was created or already exsists.
    6.     // use if you'd like to link pool references before the first spawn of a particular pool. (probably not necessary except for the most demanding of scenes.)
    7.     // Additionaly, can be used to dynamically create pools at runtime.
    8.     public static bool InitializeSpawn ( GameObject prefab ) {
    9.         return InitializeSpawn ( prefab, 0f, 0 );
    10.     }
    11.     // parameters assigned can be used to create pools at runtime
    12.     // if addPool is < 1, it will be used to increase the exsisting pool by a percentage. Otherwise it will round to the nearest integer and increase by that ammount
    13.     // minPool is the min object that must be in that pool. If the current pool + addPool < minPool, minPool will be used
    14.     public static bool InitializeSpawn ( GameObject prefab, float addPool, int minPool ) {
    15.         return InitializeSpawn( prefab, addPool, minPool, AP_enum.EmptyBehavior.Grow, AP_enum.MaxEmptyBehavior.Fail, false );
    16.     }
    17.     public static bool InitializeSpawn ( GameObject prefab, float addPool, int minPool, AP_enum.EmptyBehavior emptyBehavior, AP_enum.MaxEmptyBehavior maxEmptyBehavior ) {
    18.         return InitializeSpawn( prefab, addPool, minPool, emptyBehavior, maxEmptyBehavior, true );
    19.     }
    20.     static bool InitializeSpawn ( GameObject prefab, float addPool, int minPool, AP_enum.EmptyBehavior emptyBehavior, AP_enum.MaxEmptyBehavior maxEmptyBehavior, bool modBehavior ) {
    21.         if ( prefab == null ) { return false; } // object wasn't defined
    22.  
    23.         if ( opmScript == null ) { // object pool manager script not located yet
    24.             opmScript = Object.FindObjectOfType<AP_Manager>(); // find it in the scene
    25.             if ( opmScript == null ) { Debug.Log( "No Object Pool Manager found in scene." ); return false; } // didn't find an object pool manager
    26.         }
    27.         // found an object pool manager
    28.         return opmScript.InitializeSpawn( prefab, addPool, minPool, emptyBehavior, maxEmptyBehavior, modBehavior );
    29.     }
    30.  
    31.     // use to create a spawn of the obj prefab. returns the spawned object
    32.     public static GameObject Spawn ( GameObject prefab ) { // spawns at the position and rotation of the pool
    33.         return Spawn ( prefab, null, Vector3.zero, Quaternion.identity, false );
    34.     }
    35.     public static GameObject Spawn ( GameObject prefab, int? child ) { // child allows a single object to hold multiple versions of objects, and only activate a specific child. null = don't use children
    36.         return Spawn ( prefab, child, Vector3.zero, Quaternion.identity, false );
    37.     }
    38.     public static GameObject Spawn ( GameObject prefab, Vector3 pos, Quaternion rot ) { // specify a specific position and rotation
    39.         return Spawn ( prefab, null, pos, rot, true );
    40.     }
    41.     public static GameObject Spawn ( GameObject prefab, int? child, Vector3 pos, Quaternion rot ) {
    42.         return Spawn ( prefab, child, pos, rot, true );
    43.     }
    44.     static GameObject Spawn ( GameObject prefab, int? child, Vector3 pos, Quaternion rot, bool usePosRot ) {
    45.         FindOPM();
    46.         if ( opmScript == null ) { // didn't find an object pool manager
    47.             return null;
    48.         } else { // found an object pool manager
    49.             return opmScript.Spawn( prefab, child, pos, rot, usePosRot );
    50.         }
    51.     }
    52.  
    53.     public static bool Despawn ( GameObject obj ) {
    54.         if ( obj == null ) { return false; }
    55.         return Despawn( obj.GetComponent<AP_Reference>(), -1f );
    56.     }
    57.     public static bool Despawn ( GameObject obj, float time ) {
    58.         if ( obj == null ) { return false; }
    59.         return Despawn( obj.GetComponent<AP_Reference>(), time );
    60.     }
    61.     public static bool Despawn ( AP_Reference script ) {
    62.         return Despawn( script, -1f );
    63.     }
    64.     public static bool Despawn ( AP_Reference script, float time ) {
    65.         if ( script == null ) { return false; }
    66.         return script.Despawn( time );
    67.     }
    68.  
    69.     public static int GetActiveCount ( GameObject obj ) {
    70.         FindOPM();
    71.         if ( opmScript == null ) { // didn't find an object pool manager
    72.             return 0;
    73.         } else {
    74.             return opmScript.GetActiveCount( obj );
    75.         }
    76.     }
    77.  
    78.     public static int GetAvailableCount ( GameObject obj ) {
    79.         FindOPM();
    80.         if ( opmScript == null ) { // didn't find an object pool manager
    81.             return 0;
    82.         } else {
    83.             return opmScript.GetAvailableCount( obj );
    84.         }
    85.     }
    86.  
    87.     public static bool DespawnPool ( GameObject obj ) {
    88.         FindOPM();
    89.         if ( opmScript == null ) { // didn't find an object pool manager
    90.             return false;
    91.         } else {
    92.             return opmScript.DespawnPool( obj );
    93.         }
    94.     }
    95.  
    96.     public static bool DespawnAll () {
    97.         FindOPM();
    98.         if ( opmScript == null ) { // didn't find an object pool manager
    99.             return false;
    100.         } else {
    101.             return opmScript.DespawnAll();
    102.         }
    103.     }
    104.  
    105.     public static bool RemovePool ( GameObject obj ) {
    106.         bool result = false;
    107.         FindOPM();
    108.         if ( opmScript == null ) { // didn't find an object pool manager
    109.             return false;
    110.         } else {
    111.             result = opmScript.RemovePool( obj );
    112.             if ( result == true ) { opmScript.poolRef.Remove( obj ); }
    113.             return result;
    114.         }
    115.     }
    116.  
    117.     public static bool RemoveAll () {
    118.         FindOPM();
    119.         if ( opmScript == null ) { // didn't find an object pool manager
    120.             return false;
    121.         } else {
    122.             return opmScript.RemoveAll();
    123.         }
    124.     }
    125.  
    126.     static void FindOPM () {
    127.         if ( opmScript == null ) { // object pool manager script not located yet
    128.             opmScript = Object.FindObjectOfType<AP_Manager>(); // find it in the scene
    129.         }
    130.     }
    131.  
    132. }
    133.  
     
  8. benvanj

    benvanj

    Joined:
    Jun 26, 2018
    Posts:
    116
    Doug, Thanks for the help.... the author of the code contacted me back(after a week).... and is assisting me...
     
    Doug_B likes this.
  9. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Good stuff. Glad to hear you're back on track. :)