// **************************************************************************************************/
        //          public functions
        // **************************************************************************************************/

        /// <summary>
        /// Retrieves an instance of the specified prefab. Either returns a new instance or it claims an instance
        /// from the pool.
        /// </summary>
        /// <param name="prefab">The prefab to be instantiated.</param>
        /// <returns>
        /// An instance of the prefab.
        /// </returns>
        /// <remarks>
        /// Can be used on none-poolable objects as well. It is good practice to use <c>ObjectPoolController.Instantiate</c>
        /// whenever you may possibly make your prefab poolable in the future.
        /// </remarks>
        /// <seealso cref="Destroy(GameObject)"/>
        static public GameObject Instantiate(GameObject prefab, Transform parent = null)
        {
            PoolableObject prefabPool = prefab.GetComponent <PoolableObject>();

            if (prefabPool == null)
            {
                //Debug.LogWarning( "Object " + prefab.name + " not poolable " );
                return(( GameObject )_InstantiateGameObject(prefab, Vector3.zero, Quaternion.identity, parent)); // prefab not pooled, instantiate normally
            }

            GameObject go = _GetPool(prefabPool).GetPooledInstance(null, null, prefab.activeSelf, parent);

            return(go ?? InstantiateWithoutPool(prefab, parent));
        }
            private PoolableObject _NewPooledInstance(Vector3?position, Quaternion?rotation, bool createActive, bool addToPool)
            {
                _isDuringInstantiate = true;

                _prefab._SetActive(false);

                GameObject go = (GameObject)GameObject.Instantiate(
                    _prefab,
                    position ?? Vector3.zero,
                    rotation ?? Quaternion.identity
                    );

                _prefab._SetActive(true);

                PoolableObject poolObj = go.GetComponent <PoolableObject>();

                poolObj._pool         = this;
                poolObj._serialNumber = ++_globalSerialNumber;
                poolObj.name         += poolObj._serialNumber;

                if (poolObj.doNotDestroyOnLoad)
                {
                    GameObject.DontDestroyOnLoad(poolParent);
                }

                _pool.Add(poolObj);

                if (addToPool)
                {
                    poolObj._PutIntoPool();
                }
                else
                {
                    poolObj._usageCount++;

                    if (createActive)
                    {
                        go.SetActive(true);

                        if (poolObj.sendPoolableActivateDeactivateMessages)
                        {
                            CallMethodOnObject(poolObj.gameObject, "OnPoolableObjectActivated", true, true, poolObj.useReflectionInsteadOfMessages);
                        }
                    }
                }

                _isDuringInstantiate = false;

                return(poolObj);
            }
        /// <summary>
        /// Retrieves an instance of the specified prefab. Either returns a new instance or it claims an instance
        /// from the pool.
        /// </summary>
        /// <param name="prefab">The prefab to be instantiated.</param>
        /// <param name="position">The position in world coordinates.</param>
        /// <param name="quaternion">The rotation quaternion.</param>
        /// <returns>
        /// An instance of the prefab.
        /// </returns>
        /// <remarks>
        /// Can be used on none-poolable objects as well. It is good practice to use <c>ObjectPoolController.Instantiate</c>
        /// whenever you may possibly make your prefab poolable in the future.
        /// </remarks>
        /// <seealso cref="Destroy(GameObject)"/>
        static public GameObject Instantiate(GameObject prefab, Vector3 position, Quaternion quaternion, Transform parent = null)
        {
            PoolableObject prefabPool = prefab.GetComponent <PoolableObject>();

            if (prefabPool == null)
            {
                // no warning displayed by design because this allows to decide later if the object will be poolable or not
                // Debug.LogWarning( "Object " + prefab.name + " not poolable ");
                return(( GameObject )_InstantiateGameObject(prefab, position, quaternion, parent)); // prefab not pooled, instantiate normally
            }

            GameObject go = _GetPool(prefabPool).GetPooledInstance(position, quaternion, prefab.activeSelf, parent);

            return(go ?? InstantiateWithoutPool(prefab, position, quaternion, parent));
        }
        static internal ObjectPool _GetPool(PoolableObject prefabPoolComponent)
        {
            ObjectPool pool;

            GameObject prefab = prefabPoolComponent.gameObject;

            var instanceID = prefab.GetInstanceID();

            if (!_pools.TryGetValue(instanceID, out pool))
            {
                pool = new ObjectPool(prefab);
                _pools.Add(instanceID, pool);
            }

            return(pool);
        }
        /// <summary>
        /// Instantiates the specified prefab without using pooling.
        /// from the pool.
        /// </summary>
        /// <param name="prefab">The prefab to be instantiated.</param>
        /// <param name="position">The position in world coordinates.</param>
        /// <param name="quaternion">The rotation quaternion.</param>
        /// <returns>
        /// An instance of the prefab.
        /// </returns>
        /// <remarks>
        /// If the prefab is poolable, the <see cref="PoolableObject"/> component will be removed.
        /// This way no warning is generated that a poolable object was created without pooling.
        /// </remarks>
        static public GameObject InstantiateWithoutPool(GameObject prefab, Vector3 position, Quaternion quaternion, Transform parent = null)
        {
            _isDuringInstantiate = true;
            GameObject go = _InstantiateGameObject(prefab, position, quaternion, parent);   // prefab not pooled, instantiate normally

            _isDuringInstantiate = false;

            PoolableObject pool = go.GetComponent <PoolableObject>();

            if (pool != null)
            {
                pool._wasInstantiatedByObjectPoolController = true;
                Component.Destroy(pool);
            }

            return(go);
        }
            internal GameObject GetPooledInstance(Vector3?position, Quaternion?rotation, bool activateObject, Transform parent = null)
            {
                _ValidatePooledObjectDataContainer();

                PoolableObject instance = null;

                for (int i = 0; i < _pool.Count; i++)
                {
                    var pooledElement = _pool.ElementAt(i);

                    if (pooledElement == null)   // can happen e.g. at scene loads, so we need to clean up
                    {
                        _pool.RemoveAt(i--);
                        continue;
                    }

                    if (pooledElement._isInPool)
                    {
                        instance = pooledElement;

                        var transform = pooledElement.transform;
                        transform.position   = (position != null) ? ( Vector3 )position : _poolableObjectComponent.transform.position;
                        transform.rotation   = (rotation != null) ? ( Quaternion )rotation : _poolableObjectComponent.transform.rotation;
                        transform.localScale = _poolableObjectComponent.transform.localScale;
                        break;
                    }
                }

                if (instance == null && _pool.Count < _poolableObjectComponent.maxPoolSize)   //create and return new element
                {
                    instance = _NewPooledInstance(position, rotation, activateObject, false);
                    instance.transform.SetParent(parent, true);   //instance.transform.parent = parent;
                    return(instance.gameObject);
                }

                if (instance != null)
                {
                    instance.TakeFromPool(parent, activateObject);
                    return(instance.gameObject);
                }
                else
                {
                    return(null);
                }
            }
        /// <summary>
        /// Gets the reference to the script component, or <c>null</c> if the object was
        /// already destroyed or moved to the pool.
        /// </summary>
        /// <returns>
        /// The reference to <c>T</c> or null
        /// </returns>
        public T Get()
        {
            if (!_objComponent)
            {
                return(null);
            }

            if (_pooledObj)   // could be set to a none-poolable object
            {
                if (_pooledObj._usageCount != _initialUsageCount || _pooledObj._isInPool)
                {
                    _objComponent = null;
                    _pooledObj    = null;
                    return(null);
                }
            }
            return((T)_objComponent);
        }
        /// <summary>
        /// Preloads as many instances to the pool so that there are at least as many as
        /// specified in <see cref="PoolableObject.preloadCount"/>.
        /// </summary>
        /// <param name="prefab">The prefab.</param>
        /// <remarks>
        /// Use ObjectPoolController.isDuringPreload to check if an object is preloaded in the <c>Awake()</c> function.
        /// If the pool already contains at least <see cref="PoolableObject.preloadCount"/> objects, the function does nothing.
        /// </remarks>
        /// <seealso cref="PoolableObject.preloadCount"/>
        static public void Preload(GameObject prefab)   // adds as many instances to the prefab pool as specified in the PoolableObject
        {
            PoolableObject poolObj = prefab.GetComponent <PoolableObject>();

            if (poolObj == null)
            {
                Debug.LogWarning("Can not preload because prefab '" + prefab.name + "' is not poolable");
                return;
            }

            var pool = _GetPool(poolObj);

            //check how much Objects need to be preloaded
            int delta = poolObj.preloadCount - pool.GetObjectCount();

            if (delta <= 0)
            {
                return;
            }

            isDuringPreload = true;

            bool preloadActive = prefab.activeSelf;

            try
            {
                for (int i = 0; i < delta; i++)
                {
                    //dont use prefab.activeSelf because this may change inside Preloadinstance. use the cached value "preloadActive"
                    pool.PreloadInstance(preloadActive);
                }
            }
            finally
            {
                isDuringPreload = false;
            }

            //Debug.Log( "preloaded: " + prefab.name + " " + poolObj.preloadCount + " times" );
        }
        /// <summary>
        /// Instantiates the specified prefab without using pooling.
        /// from the pool.
        /// </summary>
        /// <param name="prefab">The prefab to be instantiated.</param>
        /// <param name="position">The position in world coordinates.</param>
        /// <param name="quaternion">The rotation quaternion.</param>
        /// <returns>
        /// An instance of the prefab.
        /// </returns>
        /// <remarks>
        /// If the prefab is poolable, the <see cref="PoolableObject"/> component will be removed.
        /// This way no warning is generated that a poolable object was created without pooling.
        /// </remarks>
        static public GameObject InstantiateWithoutPool(GameObject prefab, Vector3 position, Quaternion quaternion, Transform parent = null)
        {
            _isDuringInstantiate = true;
            GameObject go = _InstantiateGameObject(prefab, position, quaternion, parent);   // prefab not pooled, instantiate normally

            _isDuringInstantiate = false;

            PoolableObject pool = go.GetComponent <PoolableObject>();

            if (pool != null)
            {
                pool._instantiatedByObjectPoolController = true; // allows disabled game objects with deferred Awake to check if they were instantiated by ObjectPoolController
                if (pool.doNotDestroyOnLoad)
                {
                    GameObject.DontDestroyOnLoad(go);
                }

                Component.Destroy(pool);
            }

            return(go);
        }
 /// <summary>
 /// Resets the reference to <c>null</c>.
 /// </summary>
 public void Reset()
 {
     _pooledObj         = null;
     _objComponent      = null;
     _initialUsageCount = 0;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="PoolableReference&lt;T&gt;"/> class from
 /// a given <see cref="PoolableReference&lt;T&gt;"/>.
 /// </summary>
 /// <param name="poolableReference">The poolable reference.</param>
 public PoolableReference(PoolableReference <T> poolableReference)
 {
     _objComponent      = poolableReference._objComponent;
     _pooledObj         = poolableReference._pooledObj;
     _initialUsageCount = poolableReference._initialUsageCount;
 }
 internal void Remove(PoolableObject poolObj)
 {
     _pool.Remove(poolObj);
 }
 public ObjectPool(GameObject prefab)
 {
     this._prefab = prefab;
     this._poolableObjectComponent = prefab.GetComponent <PoolableObject>();
 }