提供对象缓存池的功能,避免频繁地创建和销毁各种游戏对象,提高游戏性能。除了 Game Framework 自身使用了对象池,用户还可以很方便地创建和管理自己的对象池。

E神

就Unity游戏开发来说,对象池是一个非常重要的资源管理手段

伪代码结构参照https://blog.csdn.net/yupu56/article/details/110206648?spm=1001.2014.3001.5501

伪代码

ObjectPoolManager

ObjectPoolManager 是管理不同对象池的总类 对象池的具体对象管理逻辑会在ObjectPool里面

public class ObjectPoolManager 
{
    private const int DefaultCapacity = int.MaxValue;//默认容量
    private const float DefaultExpireTime = float.MaxValue;//默认释放时间
    private const int DefaultPriority = 0;//默认优先级

    private readonly Dictionary<TypeNamePair, ObjectPoolBase> m_ObjectPools;
    private readonly List<ObjectPoolBase> m_CachedAllObjectPools;
    private readonly Comparison<ObjectPoolBase> m_ObjectPoolComparer;

    /// <summary>
    /// 初始化对象池管理器的新实例。
    /// </summary>
    public ObjectPoolManager()
    {
        m_ObjectPools = new Dictionary<TypeNamePair, ObjectPoolBase>();
        m_CachedAllObjectPools = new List<ObjectPoolBase>();
        m_ObjectPoolComparer = ObjectPoolComparer;
    }

    public int Priority;/// 获取游戏框架模块优先级。优先级较高的模块会优先轮询,并且关闭操作会后进行
    public int Count;/// 获取对象池数量。


    /// <summary>
    /// 对象池管理器轮询。
    /// </summary>
    /// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
    /// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
    internal override void Update(float elapseSeconds, float realElapseSeconds)
    {
        foreach (KeyValuePair<TypeNamePair, ObjectPoolBase> objectPool in m_ObjectPools)
        {
            objectPool.Value.Update(elapseSeconds, realElapseSeconds);
        }
    }

    /// <summary>
    /// 获取对象池。
    /// </summary>
    /// <typeparam name="T">对象类型。</typeparam>
    /// <returns>要获取的对象池。</returns>
    public IObjectPool<T> GetObjectPool<T>() where T : ObjectBase
    {
        return (IObjectPool<T>)InternalGetObjectPool(new TypeNamePair(typeof(T)));
    }

    /// <summary>
    /// 创建允许单次获取的对象池。
    /// </summary>
    /// <typeparam name="T">对象类型。</typeparam>
    /// <returns>要创建的允许单次获取的对象池。</returns>
    public IObjectPool<T> CreateSingleSpawnObjectPool<T>() where T : ObjectBase
    {
        return InternalCreateObjectPool<T>(string.Empty, false, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority);
    }

    /// <summary>
    /// 创建允许多次获取的对象池。
    /// </summary>
    /// <typeparam name="T">对象类型。</typeparam>
    /// <returns>要创建的允许多次获取的对象池。</returns>
    public ObjectPoolBase CreateMultiSpawnObjectPool<T>()
    {
        return InternalCreateObjectPool<T>(string.Empty, true, DefaultExpireTime, DefaultCapacity, DefaultExpireTime, DefaultPriority);
    }
}

ObjectPool

可以看到 ObjectPool 对泛型Object<T>类型进行管理

提供了对象获取,回收与释放方法

提供了对象定时自动释放功能

/// <summary>
/// 泛型T的对象池。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
private sealed class ObjectPool<T> : ObjectPoolBase, IObjectPool<T> where T : ObjectBase
{
    private readonly GameFrameworkMultiDictionary<string, Object<T>> m_Objects;
    private readonly Dictionary<object, Object<T>> m_ObjectMap;
    private readonly List<T> m_CachedCanReleaseObjects;
    private readonly List<T> m_CachedToReleaseObjects;

    public override Type ObjectType/// 获取对象池对象类型。

    public override int Count/// 获取对象池中对象的数量。
    public override int CanReleaseCount/// 获取对象池中能被释放的对象的数量。
    public override bool AllowMultiSpawn/// 获取是否允许对象被多次获取。
    public override float AutoReleaseInterval/// 获取或设置对象池自动释放可释放对象的间隔秒数。
    public override int Capacity/// 获取或设置对象池的容量。
    public override float ExpireTime/// 获取或设置对象池对象过期秒数。
    public override int Priority/// 获取或设置对象池的优先级。

    /// <summary>
    /// 创建对象。
    /// </summary>
    /// <param name="obj">对象。</param>
    /// <param name="spawned">对象是否已被获取。</param>
    public void Register(T obj, bool spawned)
    {
        if (obj == null)
        {
            throw new GameFrameworkException("Object is invalid.");
        }

        Object<T> internalObject = Object<T>.Create(obj, spawned);
        m_Objects.Add(obj.Name, internalObject);
        m_ObjectMap.Add(obj.Target, internalObject);

        if (Count > m_Capacity)
        {
            Release();
        }
    }

    /// <summary>
    /// 获取对象。
    /// </summary>
    /// <returns>要获取的对象。</returns>
    public T Spawn()
    {
        return Spawn(string.Empty);
    }

    /// <summary>
    /// 回收对象。
    /// </summary>
    /// <param name="obj">要回收的对象。</param>
    public void Unspawn(T obj)
    {
        if (obj == null)
        {
            throw new GameFrameworkException("Object is invalid.");
        }

        Unspawn(obj.Target);
    }

    //对象池的自动释放机制
    internal override void Update(float elapseSeconds, float realElapseSeconds)
    {
        m_AutoReleaseTime += realElapseSeconds;
        if (m_AutoReleaseTime < m_AutoReleaseInterval)
        {
            return;
        }
        Release();
    }
    /// <summary>
    /// 释放对象池中的可释放对象。
    /// </summary>
    public override void Release()
    {
        Release(Count - m_Capacity, m_DefaultReleaseObjectFilterCallback);
    }
}

Object<T>

Object<T>相当于给T类型规定了共同的行为

/// <summary>
/// 内部对象。
/// </summary>
/// <typeparam name="T">对象类型。</typeparam>
private sealed class Object<T> : IReference where T : ObjectBase
{
    private T m_Object;
    private int m_SpawnCount;

    /// <summary>
    /// 创建内部对象。
    /// </summary>
    /// <param name="obj">对象。</param>
    /// <param name="spawned">对象是否已被获取。</param>
    /// <returns>创建的内部对象。</returns>
    public static Object<T> Create(T obj, bool spawned)
    {
        Object<T> internalObject = ReferencePool.Acquire<Object<T>>();
        internalObject.m_Object = obj;
        internalObject.m_SpawnCount = spawned ? 1 : 0;
        if (spawned)
        {
            obj.OnSpawn();
        }

        return internalObject;
    }

    /// <summary>
    /// 获取对象。
    /// </summary>
    /// <returns>对象。</returns>
    public T Spawn()
    {
        m_SpawnCount++;
        m_Object.LastUseTime = DateTime.Now;
        m_Object.OnSpawn();
        return m_Object;
    }

    /// <summary>
    /// 回收对象。
    /// </summary>
    public void Unspawn()
    {
        m_Object.OnUnspawn();
        m_Object.LastUseTime = DateTime.Now;
        m_SpawnCount--;
        if (m_SpawnCount < 0)
        {
            throw new GameFrameworkException(Utility.Text.Format("Object '{0}' spawn count is less than 0.", Name));
        }
    }

    /// <summary>
    /// 释放对象。
    /// </summary>
    /// <param name="isShutdown">是否是关闭对象池时触发。</param>
    public void Release(bool isShutdown)
    {
        m_Object.Release(isShutdown);
        ReferencePool.Release(m_Object);
    }
}

小结

GF对象池实现了对象池的基本功能

多个对象池的统一管理

对象的获取回收与释放,对象的复用

对象的自动释放机制

实际使用,简洁引用关系图

使用实践

using GameFramework;
using StarForce;
using GameFramework.Resource;
using GameFramework.ObjectPool;

public class TestNode:MonoBehaviour
{

    public GameObject testObj;
//Cube预制
    public List<GameObject> objlist=new List<GameObject>();

    private IObjectPool<TestObject> TestObjectPool = null;

    private void Awake()
    {
    
    }

    private void Start()
    {
        TestObjectPool = GameEntry.ObjectPool.CreateSingleSpawnObjectPool<TestObject>(5f);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.N))
        {
            GameObject obj;
            obj = Instantiate(testObj);
            objlist.Add(obj);
            TestObjectPool.Register(TestObject.Create(obj),true);
        }

        if (Input.GetKeyDown(KeyCode.M))
        {
            Debug.LogError("回收对象");
            objlist[0].SetActive(false);
            TestObjectPool.Unspawn(objlist[0]);
            objlist.RemoveAt(0);
        }
    }


}

public class TestObject : ObjectBase
{
    public static TestObject Create(object target)
    {
        Debug.LogError("创建对象");

        TestObject testObject = ReferencePool.Acquire<TestObject>();
        testObject.Initialize(target);
        return testObject;
    }

    protected override void Release(bool isShutdown)
    {

        
        GameObject testMonoObject = (GameObject)Target;
        if (testMonoObject == null)
        {
            return;
        }
        Debug.LogError("释放对象");

        Object.Destroy(testMonoObject.gameObject);
    }
}
运行结果