文章目录
GameObject对象池
类
- IManager
- IModel
- GameObjectPool
- ObjectPoolManager
方法
ObjectPoolManager
CreateGameObjectPool
创建对象池
DestroyGameObjectPool
删除对象池
GetGameObject
获得某个对象池里的对象
RecycleGameObject
回收对象
GameObjectPool
ClearAll
清除所有信息
GetGameObject
获得对象
RecycleGameObject
回收对象
ClearRedundantObjects
清除多余对象
CreateGameObjecet
创建对象
使用方法
//创建对象池(默认大小5)
ObjectPoolManager.Instance.CreateGameObjectPool("Basketball", "Basketball",20);
//获得某个对象池中对象
GameObject obj = ObjectPoolManager.Instance.GetGameObject("Basketball");
//回收对象
ObjectPoolManager.Instance.RecycleGameObject("Basketball",gameObject);
//删除对象池
ObjectPoolManager.Instance.DestroyGameObjectPool("Basketball");
全部代码
GameObjectPool
using MGPMFramework;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class GameObjectPool : IModel
{
private int m_Number;
private int m_PoolSize;
private string m_ResName;
private GameObject m_OriginalRes;
private GameObject m_GameObjectPoolParent;
private Queue<GameObject> m_NotUseGameObjectPool;
private bool m_SuccessFlag;
public bool SuccessFlag { get { return m_SuccessFlag; } }
public GameObjectPool(string name, string resName, GameObject objectPool, int poolSize)
{
m_Number = 0;
m_SuccessFlag = true;
m_NotUseGameObjectPool = new Queue<GameObject>(poolSize);
m_PoolSize = poolSize;
m_ResName = resName;
string poolName = name + "Pool";
m_GameObjectPoolParent = new GameObject(poolName);
m_GameObjectPoolParent.transform.parent = objectPool.transform;
OnInit();
}
/// <summary>
/// 清除所有信息
/// </summary>
public void ClearAll()
{
while (m_NotUseGameObjectPool.Count > 0) Object.Destroy(m_NotUseGameObjectPool.Dequeue());
m_NotUseGameObjectPool = null;
m_PoolSize = 0;
m_ResName = string.Empty;
m_OriginalRes = null;
Object.Destroy(m_GameObjectPoolParent);
ResourcesManager.Instance.UnloadUnusedAssets();
}
/// <summary>
/// 获得对象
/// </summary>
/// <returns></returns>
public GameObject GetGameObject()
{
lock (m_NotUseGameObjectPool)
{
if (m_NotUseGameObjectPool.Count > 0)
{
return m_NotUseGameObjectPool.Dequeue();
}
else
{
GameObject obj = CreateGameObjecet();
if (obj != null) return obj;
else return null;
}
}
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="obj"></param>
public void RecycleGameObject(GameObject obj)
{
lock (m_NotUseGameObjectPool)
{
if (!m_NotUseGameObjectPool.Contains(obj))
{
obj.SetActive(false);
obj.transform.parent = m_GameObjectPoolParent.transform;
obj.transform.localPosition = Vector3.zero;
m_NotUseGameObjectPool.Enqueue(obj);
}
else
{
Debug.LogError($"该对象已经归还过了,对象名{obj.name}");
}
ClearRedundantObjects();
}
}
/// <summary>
/// 清除多余对象
/// </summary>
private void ClearRedundantObjects()
{
while (m_NotUseGameObjectPool.Count > m_PoolSize) Object.Destroy(m_NotUseGameObjectPool.Dequeue());
}
/// <summary>
/// 创建新对象
/// </summary>
/// <returns></returns>
private GameObject CreateGameObjecet()
{
GameObject obj = GameObject.Instantiate(m_OriginalRes, m_GameObjectPoolParent.transform);
if (obj != null)
{
obj.name = m_ResName +"_"+ m_Number;
m_Number++;
if (m_Number >= 1000) m_Number = 0;
obj.SetActive(false);
obj.transform.localPosition = Vector3.zero;
return obj;
}
else
{
Debug.LogError($"实例化对象为空,资源名为{m_ResName}");
return null;
}
}
public void OnInit()
{
m_OriginalRes = ResourcesManager.Instance.Load<GameObject>(m_ResName);
if (m_OriginalRes != null)
{
for (int i = 0; i < m_PoolSize; i++)
{
GameObject obj = CreateGameObjecet();
if (obj != null) m_NotUseGameObjectPool.Enqueue(obj);
else
{
m_SuccessFlag = false;
break;
}
}
}
else
{
Debug.LogError($"资源{m_ResName}未找到");
ClearAll();
m_SuccessFlag = false;
}
}
}
ObjectPoolManager
using System.Collections.Generic;
using UnityEngine;
using MGPCommons.Class;
public class ObjectPoolManager : SingletonSuperMono<ObjectPoolManager>, IManager
{
private GameObject m_ObjectPool;
private Dictionary<string, GameObjectPool> m_AllObjectPoll;
//初始化池
//
private void Awake()
{
OnInit();
}
public void OnInit()
{
m_ObjectPool = new GameObject("ObjectPool");
DontDestroyOnLoad(m_ObjectPool);
m_AllObjectPoll = new Dictionary<string, GameObjectPool>();
}
/// <summary>
/// 创建对象池
/// </summary>
/// <param name="poolName">对象池名字</param>
/// <param name="resName">资源名</param>
/// <param name="poolSize">对象池大小</param>
public void CreateGameObjectPool(string poolName, string resName,int poolSize = 5)
{
if (!m_AllObjectPoll.ContainsKey(poolName.Trim()))
{
GameObjectPool pool = new GameObjectPool(poolName, resName, m_ObjectPool, poolSize);
if (pool.SuccessFlag) m_AllObjectPoll.Add(poolName, pool);
else pool = null;
}
else
{
Debug.LogError($"对象池{poolName}Pool已经存在");
}
}
/// <summary>
/// 删除对象池
/// </summary>
/// <param name="name"></param>
public void DestroyGameObjectPool(string poolName)
{
if (m_AllObjectPoll.ContainsKey(poolName.Trim()))
{
m_AllObjectPoll[poolName].ClearAll();
m_AllObjectPoll.Remove(poolName);
}
else
{
Debug.LogError($"对象池{poolName}Pool不存在");
}
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="poolName"></param>
/// <returns></returns>
public GameObject GetGameObject(string poolName)
{
if (m_AllObjectPoll.ContainsKey(poolName.Trim()))
{
return m_AllObjectPoll[poolName].GetGameObject();
}
else
{
Debug.LogError($"对象池{poolName}Pool不存在");
return null;
}
}
/// <summary>
/// 回收对象
/// </summary>
/// <param name="poolName"></param>
/// <param name="obj"></param>
public void RecycleGameObject(string poolName,GameObject obj)
{
if (m_AllObjectPoll.ContainsKey(poolName.Trim()))
{
m_AllObjectPoll[poolName].RecycleGameObject(obj);
}
else
{
Debug.LogError($"对象池{poolName}Pool不存在");
}
}
}
IManager
public interface IManager
{
public void OnInit();
}
IModel
public interface IModel
{
public void OnInit();
}
移植使用注意
ObjectPoolManager
继承的单例类替换GameObjectPool.OnInit
中ResourcesManager.Instance.Load<GameObject>(ResName)
替换GameObjectPool.ClearAll
中ResourcesManager.Instance.UnloadUnusedAssets()
卸载资源替换- 单例类和ResourcesManager在其它同专栏内。
问题记录
问题描述
工程启动以后,创建的所有子对象,竟然全部被删除了
触发环境
- 生成的对象有一个自定义脚本,该脚本的OnEnable中调用了三秒后回收本对象(类似子弹)
- 场景中有一个拖拽的子弹(非脚本生成,而是制作子弹时候的本体,本应删除,但是因遗漏可能没删除)
产生原因
- 有以上环境以后,项目启动,场景中的原物体也会触发OnEnable,进行回收。
- 根据逻辑,队列中会出现11个(假设默认数量是10),然后就会删除第一个,在每个对象被生成的时候,也会调用一次OnEnable,所以第一个虽然被删除了,但是依旧会被回收,然后第二个就会被删除,依次类推。
结论
- 审查认为是使用Bug,所以做个记录,不进行修改,不要在OnEnable中调用回收函数
- 也不要在Start中调用,因为Start全局中调用一次。
- 场景中不要有遗留原物体
更新记录
- 2023/3/23 第一次更新
- 2023/4/18 更新了创建的子对象名称区别