Unity对象池的做法

从unity官方论坛上看来的。原版为英文http://forum.unity3d.com/threads/simple-reusable-object-pool-help-limit-your-instantiations.76851/

纹理池可以存储游戏中经常复用的对象,并允许用户从其中获取对象,并且区分这两种情况:获得已有的对象或者无论如果都返回一个可用的对象(没有就新建)。

步骤如下:

  • 在prefab array里存入想初始化的预设。
  • 对每个预设,设定初始化的数量(一开始就初始化一定数量的对象)。有默认数量。
  • 调用ObjectPool.instance.GetObjectForType(objectType,onlyPooled)时。如果onlyPooled为true:只有当池里有对象时才会返回对象否则返回空。如果是false:会新建一个对象返回。如果想控制池中的对象数量的话,用true。
  • 保证所有从池中拿东西的人都知道自己什么时候要把对象还回池里.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class ObjectPool : MonoBehaviour
{
   
    public static ObjectPool instance;
   
    /// <summary>
    /// The object prefabs which the pool can handle.
    /// </summary>
    public GameObject[] objectPrefabs;
   
    /// <summary>
    /// The pooled objects currently available.
    /// </summary>
    public List<GameObject>[] pooledObjects;
   
    /// <summary>
    /// The amount of objects of each type to buffer.
    /// </summary>
    public int[] amountToBuffer;
   
    public int defaultBufferAmount = 3;
   
    /// <summary>
    /// The container object that we will keep unused pooled objects so we dont clog up the editor with objects.
    /// </summary>
    protected GameObject containerObject;
   
    void Awake ()
    {
        instance = this;
    }
   
    // Use this for initialization
    void Start ()
    {
        containerObject = new GameObject("ObjectPool");
       
        //Loop through the object prefabs and make a new list for each one.
        //We do this because the pool can only support prefabs set to it in the editor,
        //so we can assume the lists of pooled objects are in the same order as object prefabs in the array
        pooledObjects = new List<GameObject>[objectPrefabs.Length];
       
        int i = 0;
        foreach ( GameObject objectPrefab in objectPrefabs )
        {
            pooledObjects[i] = new List<GameObject>(); 
           
            int bufferAmount;
           
            if(i < amountToBuffer.Length) bufferAmount = amountToBuffer[i];
            else
                bufferAmount = defaultBufferAmount;
           
            for ( int n=0; n<bufferAmount; n++)
            {
                GameObject newObj = Instantiate(objectPrefab) as GameObject;
                newObj.name = objectPrefab.name;
                PoolObject(newObj);
            }
           
            i++;
        }
    }
   
    /// <summary>
    /// Gets a new object for the name type provided.  If no object type exists or if onlypooled is true and there is no objects of that type in the pool
    /// then null will be returned.
    /// </summary>
    /// <returns>
    /// The object for type.
    /// </returns>
    /// <param name='objectType'>
    /// Object type.
    /// </param>
    /// <param name='onlyPooled'>
    /// If true, it will only return an object if there is one currently pooled.
    /// </param>
    public GameObject GetObjectForType ( string objectType , bool onlyPooled )
    {
        for(int i=0; i<objectPrefabs.Length; i++)
        {
            GameObject prefab = objectPrefabs[i];
            if(prefab.name == objectType)
            {
               
                if(pooledObjects[i].Count > 0)
                {
                    GameObject pooledObject = pooledObjects[i][0];
                    pooledObjects[i].RemoveAt(0);
                    pooledObject.transform.parent = null;
                    pooledObject.SetActiveRecursively(true);
                   
                    return pooledObject;
                   
                } else if(!onlyPooled) {
                    return Instantiate(objectPrefabs[i]) as GameObject;
                }
               
                break;
               
            }
        }
           
        //If we have gotten here either there was no object of the specified type or non were left in the pool with onlyPooled set to true
        return null;
    }
   
    /// <summary>
    /// Pools the object specified.  Will not be pooled if there is no prefab of that type.
    /// </summary>
    /// <param name='obj'>
    /// Object to be pooled.
    /// </param>
    public void PoolObject ( GameObject obj )
    {
        for ( int i=0; i<objectPrefabs.Length; i++)
        {
            if(objectPrefabs[i].name == obj.name)
            {
                obj.SetActiveRecursively(false);
                obj.transform.parent = containerObject.transform;
                pooledObjects[i].Add(obj);
                return;
            }
        }
    }
   
}
 
 

下面是作者使用的例子:Effect.cs and SoundEffect.cs

using UnityEngine;
using System.Collections;
 
public class Effect : MonoBehaviour
{
    /// <summary>
    /// The array of emitters to fire when the effect starts.
    /// </summary>
    public ParticleEmitter[] emitters;
   
    /// <summary>
    /// The length of the effect in seconds.  After which the effect will be reset and pooled if needed.
    /// </summary>
    public float effectLength = 1f;
   
   
    /// <summary>
    /// Should the effect be added to the effects pool after completion.
    /// </summary>
    public bool poolAfterComplete = true;
   
 
   
    /// <summary>
    /// Resets the effect.
    /// </summary>
    public virtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        } else {
            Destroy(gameObject);
        }
    }
   
    /// <summary>
    /// Starts the effect.
    /// </summary>
    public virtual void StartEffect ()
    {
        foreach ( ParticleEmitter emitter in emitters )
        {
            emitter.Emit();
        }
       
        StartCoroutine(WaitForCompletion());
    }
   
    public IEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yield return new WaitForSeconds(effectLength);
       
        //Reset the now completed effect
        ResetEffect();
       
    }
   
   
   
}
using UnityEngine;
using System.Collections;
 
public class SoundEffect : MonoBehaviour
{
   
    /// <summary>
    /// The sound source that will be played when the effect is started.
    /// </summary>
    public AudioSource soundSource;
   
    /// <summary>
    /// The sound clips that will randomly be played if there is more than 1.
    /// </summary>
    public AudioClip[] soundClips;
   
    /// <summary>
    /// The length of the effectin seconds.
    /// </summary>
    public float effectLength = 1f;
   
    /// <summary>
    /// Should the effect be pooled after its completed.
    /// </summary>
    public bool poolAfterComplete = true;
   
   
   
    /// <summary>
    /// Resets the effect.
    /// </summary>
    public virtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        } else {
            Destroy(gameObject);
        }
    }
   
    /// <summary>
    /// Starts the effect.
    /// </summary>
    public virtual void StartEffect ()
    {
        soundSource.PlayOneShot(soundClips[Random.Range(0,soundClips.Length)]);
       
        StartCoroutine(WaitForCompletion());
    }
   
    public IEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yield return new WaitForSeconds(effectLength);
       
        //Reset the now completed effect
        ResetEffect();
       
    }
   
   
}

猜你喜欢

转载自berry-gong.iteye.com/blog/2168405