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