从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(); } }