共计 3014 个字符,预计需要花费 8 分钟才能阅读完成。
一:目标
内存治理是软件开发中重要的一项,在游戏中,有一些须要频繁创立和销毁的对象,例如射击游戏中的子弹,跑酷游戏中的障碍物等,通常的办法是应用 Instantiate 和 Destroy,一直的开拓和开释内存,然而这样的操作是致命的,会产生内存碎片
什么是内存碎片:内存碎片意味着在堆中的空余空间被打碎成了很多小的内存碎片,而不是大的间断内存块,总共可用内存兴许很大,然而最长的间断空间可能很小很小
例如下图所示,假如咱们最初还有 20 个空余字节,然而被一块正在应用的内存 O2 宰割成了两局部,这时咱们尝试调配 15 字节的对象就会失败,最终导致游戏解体
所有咱们能够定义一个池对象,其中蕴含了一组可重用的对象
当须要新对象时,向池子要一个,如果池子中没有此对象,就 Instantiate 一个,如果池子中存在此对象,则间接 SetActive=true
当须要销毁时,不应用 Destroy,间接 SetActive=false 并放回池子
通过这种形式能够轻易地创立和销毁对象而不用分配内存或其余资源
二:解决的问题及长处
——防止分配内存和开释内存产生的内存碎片导致的游戏解体
三:应用
——将所有预制体文件对立放在 Resources 文件夹下的 Prefabs 文件夹的子文件夹下
——每个对象池物体的脚本继承 ReusableObj 类,并实现 OnSpawn 和 OnUnSpawn 办法,重写 Reset 办法
——应用 ObjectPoolMgr.Ins.XXX
ObjectPoolMgr.Ins.Allocate("Effect");
ObjectPoolMgr.Ins.Recycle(gameObject);
四:代码实现
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 对象池管理器
/// </summary>
public class ObjectPoolMgr : Singleton<ObjectPoolMgr>
{
public const string ResDir = "Prefabs/";// 资源目录
private Dictionary<string, SubPool> poolCache = new Dictionary<string, SubPool>();// 所有的池子
#region Main
/// <summary>
/// 分配资源
/// </summary>
public GameObject Allocate(string resName)
{if (!poolCache.ContainsKey(resName))
{if (!CreatePool(resName))
{Debug.LogError("创立池子失败:" + resName);
return null;
}
}
return poolCache[resName].Allocate();}
/// <summary>
/// 回收资源
/// </summary>
public void Recycle(GameObject obj)
{string poolName = obj.GetComponent<ReuseableObj>().HostPoolId;
poolCache[poolName].Recycle(obj);
}
#endregion
/// <summary>
/// 创立池子
/// </summary>
private bool CreatePool(string resName)
{
string path = ResDir + resName;
GameObject prefab = Resources.Load<GameObject>(path);
if (prefab == null)
{return false;}
SubPool subPool = new SubPool(resName, prefab);
poolCache.Add(resName, subPool);
return true;
}
}
/// <summary>
/// 子池子
/// </summary>
public class SubPool
{
public string poolId;// 池子名称
public GameObject prefab;// 预制体
public Stack<GameObject> unUsedObjCache = new Stack<GameObject>();// 池子中所有未应用的对象
/// <summary>
/// 初始化池子
/// </summary>
public SubPool(string poolId, GameObject prefab)
{
this.poolId = poolId;
this.prefab = prefab;
}
/// <summary>
/// 分配资源
/// </summary>
public GameObject Allocate()
{GameObject obj = GetUnusedObj();
if (obj == null)
{obj = SpawnObj();
}
obj.GetComponent<ReuseableObj>().OnSpawn();
obj.SetActive(true);
return obj;
}
/// <summary>
/// 回收资源
/// </summary>
public void Recycle(GameObject obj)
{obj.SetActive(false);
unUsedObjCache.Push(obj);
obj.GetComponent<ReuseableObj>().OnUnSpawn();
obj.GetComponent<ReuseableObj>().Reset();
}
/// <summary>
/// 生成对象
/// </summary>
public GameObject SpawnObj()
{GameObject obj = Object.Instantiate(prefab);
obj.GetComponent<ReuseableObj>().HostPoolId = poolId;
return obj;
}
/// <summary>
/// 从池子中失去一个未应用的对象
/// </summary>
private GameObject GetUnusedObj()
{
GameObject obj = null;
if (unUsedObjCache.Count <= 0) return null;
obj = unUsedObjCache.Pop();
return obj;
}
}
using UnityEngine;
/// <summary>
/// 对象池复用的物体
/// </summary>
public abstract class ReuseableObj : MonoBehaviour
{
// 隶属的池子
private string hostPoolId;
public string HostPoolId
{
get
{return hostPoolId;}
set
{hostPoolId = value;}
}
/// <summary>
/// 取出时
/// </summary>
public abstract void OnSpawn();
/// <summary>
/// 回收时
/// </summary>
public abstract void OnUnSpawn();
/// <summary>
/// 重置
/// </summary>
public abstract void Reset();}
图片起源:http://www.hp91.cn/ 网页游戏
正文完