在游戏的制做过程当中,咱们可能会碰到这样的状况,开枪的时候射出子弹,每一个子弹即一个对象,正常状况,咱们的处理方式可能会是每开一枪就Instantiate一个新的子弹,当子弹到达极限距离或者碰到物体后再Destroy销毁它。假设有射出1000发子弹,咱们就会执行1000次这样的操做,反复建立销毁是一个内存反复分配与释放的过程,很容易产生内存碎片。在Unity中Instantiate和Destroy操做,不只影响性能还容易产生内存碎片,在Unity中建立或是销毁对象须要付出昂贵的代价的。而用对象池能够解决性能开销问题ide
内存碎片:
内存碎片的意思是内存被分红一个一个的小块而不是整个大块,全部内存小块的大小可能很大但并不能使用,好比你想分配16byte的内存,此时若是有 20byte的空间就能够分配成功,可是若是这20byte是内存碎片,为两个10byte就会分配失败。因此,若是存在大量内存碎片,理论上有足够的可用内存,也会分配失败
不少游戏公司的游戏都会进行浸泡测试,让一个游戏跑好几天,查看是否崩溃来检测内存泄露等等,由于内存碎片产生毁灭性的结果是一个缓慢的过程性能
池能够理解为咱们现实生活中的游泳池,里面装满了水,而在计算机世界里称为必定数量水的集合。因此池的概念和集合很类似。例如内存池就是必定数量的已经分配好的内存的集合。线程池就是必定数量的已经建立好的线程的集合,那么,对象池,顾名思义就是必定数量的已经建立好的对象(Object)的集合
对象池的原理就是预先分配一大块内存,生成满须要常常用的对象,而后直到不使用再所有释放测试
对象池就是复用池中对象,没有分配内存和建立堆中对象的开销,进而减小垃圾收集器的负担, 避免内存抖动this
在制做过程当中当常常有同一个Prefab要用到屡次,须要反复实例化(Instantiate)和销毁(Desroy)。例如射击游戏中的子弹,跑酷游戏中的障碍物,路径等.....
线程
在游戏加载时把一批Prefab实例化好放在对象池中,游戏中用的时候拿出来(SetActive=true),不用的时候放回去(SetActive=false),避免反复实例化和销毁。能够理解为对象池就是一个租借处,须要的时候借出去,用完了再还回来code
——————————————————————ReusableObject脚本orm
using UnityEngine; /// <summary> /// 对象池中的每一个物体都须要重写取出和放回的方法 /// </summary> public abstract class ReusableObject : MonoBehaviour { /// <summary> /// 取出时 /// </summary> public abstract void OnSpawn(); /// <summary> /// 回收时 /// </summary> public abstract void OnUnSpawn(); }
——————————————————————SubPool脚本 对象
using UnityEngine; using System.Collections.Generic; /// <summary> /// 每一个子池子 /// </summary> public class SubPool { //预制体 private GameObject prefab; //父物体 private Transform parent; //当前子池子中的全部物体 private List<GameObject> goList = new List<GameObject>(); /// <summary> /// 初始化当前子池子 /// </summary> /// <param name="prefab">预制体</param> /// <param name="parent">父物体</param> public SubPool(GameObject prefab, Transform parent) { this.prefab = prefab; this.parent = parent; } #region public方法 /// <summary> /// 取出物体 /// </summary> public GameObject Spawn() { GameObject go = null; go = GetGoFromList(); if (go == null) { go = GameObject.Instantiate(prefab, parent); goList.Add(go); } go.GetComponent<ReusableObject>().OnSpawn();//取出物体时执行的方法 go.SetActive(true); return go; } /// <summary> /// 回收物体 /// </summary> /// <param name="go">要回收的物体</param> public void UnSpawn(GameObject go) { go.GetComponent<ReusableObject>().OnUnSpawn();//回收物体时执行的方法 go.SetActive(false); } /// <summary> /// 回收全部物体 /// </summary> public void UnSpawnAll() { foreach (var temp in goList) { if (temp.activeSelf) { UnSpawn(temp); } } } /// <summary> /// 当前子池子中是否包含此游戏物体 /// </summary> /// <param name="go">判断的游戏物体</param> public bool Contains(GameObject go) { return goList.Contains(go); } #endregion #region private方法 /// <summary> /// 从goList中获得一个物体 /// </summary> /// <returns></returns> private GameObject GetGoFromList() { GameObject go = null; foreach (var temp in goList) { if (temp.activeSelf == false) { go = temp; } } return go; } #endregion }
——————————————————————ObjectPool脚本 游戏
using UnityEngine; using System.Collections.Generic; /// <summary> /// 对象池总管理器 /// </summary> public class ObjectPool : MonoBehaviour { //单例 public static ObjectPool Instance { get; set; } //每一个对象池物体信息的字典 private Dictionary<string, Transform> poolInfoDict = new Dictionary<string, Transform>(); //每一个子池子的字典 private Dictionary<string, SubPool> subPoolDict = new Dictionary<string, SubPool>(); [Header("资源目录")] public string resDir; [Header("手动添加全部对象池物体")] [Space(25)] public ObjectInfo[] objects; private void Awake() { Instance = this; //初始化每一个对象池物体信息的字典 foreach (var o in objects) { if (!poolInfoDict.ContainsKey(o.resName)) { poolInfoDict.Add(o.resName, o.parent); } } } #region main /// <summary> /// 取出物体 /// </summary> /// <param name="resName">资源名称</param> public GameObject Spawn(string resName) { GameObject go = null; if (!subPoolDict.ContainsKey(resName)) { if (!CreatePool(resName)) { Debug.LogWarning("建立池子失败:" + resName); return go; } } SubPool pool = subPoolDict[resName]; go = pool.Spawn();//取出物体 return go; } /// <summary> /// 回收物体 /// </summary> /// <param name="go">要回收的物体</param> public void UnSpawn(GameObject go) { foreach (var pool in subPoolDict.Values) { if (pool.Contains(go)) { pool.UnSpawn(go); break; } } } /// <summary> /// 回收全部物体 /// </summary> public void UnSpawnAll() { foreach (var pool in subPoolDict.Values) { pool.UnSpawnAll(); } } #endregion #region private方法 /// <summary> /// 建立池子 /// </summary> /// <param name="resName">资源名称</param> private bool CreatePool(string resName) { if (!poolInfoDict.ContainsKey(resName)) { Debug.LogWarning("不存在此子池子:" + resName + ",请在面板中手动添加资源名称"); return false; } string path = resDir + resName; GameObject prefab = Resources.Load<GameObject>(path); if (prefab == null) { Debug.LogWarning("路径不正确:" + path); return false; } SubPool pool = new SubPool(prefab, poolInfoDict[resName]); subPoolDict.Add(resName, pool); return true; } #endregion } /// <summary> /// 每一个对象池中的物体信息 /// </summary> [System.Serializable] public class ObjectInfo { //资源名称 public string resName; //父物体 public Transform parent; }