Unity性能优化之对象池管理器PoolManager

版权声明:By XM肖牧 https://blog.csdn.net/yye4520/article/details/89147558

简介

什么是对象池?顾名思义,就是存放实例对象的池子,即缓冲区。一般对象池在初始化时会包含着若干个实例对象,当我们需要时便从池子里取出来,当不需要时便放回对象池里面。使用对象池不需要频繁的产生和销毁实例对象,当对象池中的实例对象不够用时才会继续产生实例对象,这大大的节省了性能。所以在很多频繁使用实例对象的场景中,我们常常可以看到对象池的身影,比如数据库连接池、线程池、任务队列池和大量的游戏场景。

PoolManager

我在空余时间写了一个unity的对象池管理PoolManager,除了实现了一般对象池功能,还对其做出了拓展,比如自动回收,自动删除长时间没用的对象,实例对象数量的限制等等,大家可以根据自己项目的需求对代码进行修改和拓展。

// <Licensing>
// Copyright (C) XM.All Rights Reserved.
// Author: 吴肖牧(XM)
// Date: 2019-03-26
// Desc: 对象池管理器
// <Licensing>

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XMFramework;

public class PoolManager : GameBase
{
    private Dictionary<string, SpawnPool> _pools = new Dictionary<string, SpawnPool>();

    public Dictionary<string, SpawnPool> GetPools()
    {
        return _pools;
    }

    public bool CreatePool(string poolName)
    {
        if (_pools.TryGetValue(poolName, out SpawnPool spawnPool))
        {
            XMDebug.Log("已存在对象池", poolName);
            return false;
        }
        SpawnPool pool = new GameObject(poolName + "Pool").AddComponent<SpawnPool>();
        pool.transform.SetParent(transform);
        pool.poolName = poolName;
        _pools.Add(poolName, pool);
        return true;
    }

    public bool RemovePool(string poolName)
    {
        if (!_pools.TryGetValue(poolName, out SpawnPool spawnPool))
        {
            XMDebug.Log("找不到对象池", poolName);
            return false;
        }
        spawnPool.Clean();
        Destroy(spawnPool.gameObject);
        Util.ClearMemory();
        return true;
    }

    public SpawnPool GetSpawnPool(string poolName)
    {
        if (!_pools.TryGetValue(poolName, out SpawnPool spawnPool))
        {
            XMDebug.Log("找不到对象池", poolName);
            return null;
        }
        return _pools[poolName];
    }

    public bool ContainsKey(string poolName)
    {
        return _pools.ContainsKey(poolName);
    }

    public bool ContainsValue(SpawnPool pool)
    {
        return _pools.ContainsValue(pool);
    }

    public void CleanPool()
    {
        foreach (KeyValuePair<string, SpawnPool> pair in _pools)
        {
            if (pair.Value.gameObject)
            {
                Destroy(pair.Value.gameObject);
            }
        }
        _pools.Clear();
        Util.ClearMemory();
    }
}
// <Licensing>
// Copyright (C) XM.All Rights Reserved.
// Author: 吴肖牧(XM)
// Date: 2019-04-02
// Desc: 对象池生产器
// <Licensing>

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XMFramework;

public class SpawnPool : GameBase
{
    public string poolName = "";

    [SerializeField]
    private List<PrefabPool> _prefabPools = new List<PrefabPool>();

    private List<Transform> _spawned = new List<Transform>();//存放所有对象,暂时没用到

    #region Prefab
    public void AddPrefab(PrefabPool prefabPool)
    {
        if (_prefabPools.Contains(prefabPool))
        {
            XMDebug.Log("已存在对象", prefabPool);
            return;
        }

        prefabPool.prefabScale = prefabPool.prefab.localScale;

        _prefabPools.Add(prefabPool);

        if (prefabPool.initDespawnCount > 0)
        {
            for (int i = 0; i < prefabPool.initDespawnCount; i++)
            {
                Transform inst = Instantiate<Transform>(prefabPool.prefab, Vector3.zero, Quaternion.identity, transform);
                prefabPool._despawned.Add(inst);
                inst.name = inst.name.Replace("(Clone)", "");
                inst.gameObject.SetActive(false);
            }
        }

        StartCoroutine(TidyDespawn(prefabPool));
    }

    public void DelPrefab(PrefabPool prefabPool)
    {
        if (_prefabPools.Contains(prefabPool))
        {
            _prefabPools.Remove(prefabPool);
        }
        else
        {
            XMDebug.Log("找不到对象", prefabPool);
        }
    }
    #endregion

    #region SpawnPrefab
    public Transform Spawn(Transform prefab)
    {
        return Spawn(prefab, Vector3.zero, Quaternion.identity);
    }

    public Transform Spawn(Transform prefab, Transform parent)
    {
        return Spawn(prefab, Vector3.zero, Quaternion.identity, parent);
    }

    public Transform Spawn(Transform prefab, Vector3 pos, Quaternion rot)
    {
        Transform inst = Spawn(prefab, pos, rot, transform);

        if (inst == null) return null;

        return inst;
    }

    public Transform Spawn(Transform prefab, Vector3 pos, Quaternion rot, Transform parent)
    {
        Transform inst = Spawn(prefab.name, pos, rot, parent);

        return inst;
    }
    #endregion

    #region SpawnPrefabName
    public Transform Spawn(string prefabName)
    {
        return Spawn(prefabName, Vector3.zero, Quaternion.identity);
    }

    public Transform Spawn(string prefabName, Transform parent)
    {
        return Spawn(prefabName, Vector3.zero, Quaternion.identity, parent);
    }

    public Transform Spawn(string prefabName, Vector3 pos, Quaternion rot)
    {
        Transform inst = Spawn(prefabName, pos, rot, transform);

        if (inst == null) return null;

        return inst;
    }

    public Transform Spawn(string prefabName, Vector3 pos, Quaternion rot, Transform parent)
    {
        Transform inst = null;

        for (int i = 0; i < _prefabPools.Count; i++)
        {
            PrefabPool prefabPool = _prefabPools[i];
            if (prefabPool.prefab.name == prefabName)
            {
                if (prefabPool.spawnMaxLimit > 0 && prefabPool._spawned.Count >= prefabPool.spawnMaxLimit)
                {
                    return null;
                }

                if (prefabPool._despawned.Count > 0)
                {
                    inst = prefabPool._despawned[0];
                    prefabPool._despawned.RemoveAt(0);
                    inst.gameObject.SetActive(true);
                }
                else
                {
                    inst = Instantiate<Transform>(prefabPool.prefab, pos, rot, parent);
                    inst.name = inst.name.Replace("(Clone)", "");
                }

                prefabPool._spawned.Add(inst);

                if (prefabPool.autoDespawnTime > 0)
                {
                    StartCoroutine(AutoDespawn(inst, prefabPool.autoDespawnTime));
                }
                break;
            }
        }

        if (inst == null) return null;

        _spawned.Add(inst);

        return inst;
    }

    #endregion

    #region Despawn
    /// <summary>
    /// 销毁对象,销毁传的对象
    /// </summary>
    /// <param name="prefab">对象</param>
    public void Despawn(Transform prefab)
    {
        if (prefab == null)
        {
            return;
        }
        Transform inst = null;

        for (int i = 0; i < _prefabPools.Count; i++)
        {
            PrefabPool prefabPool = _prefabPools[i];
            if (prefabPool.prefab.name == prefab.name)
            {
                if (prefabPool._spawned.Count > 0)
                {
                    if (prefabPool._spawned.Contains(prefab))
                    {
                        inst = prefab;
                        if (prefabPool.despawnMaxLimit != 0)
                        {
                            if (prefabPool._despawned.Count < prefabPool.despawnMaxLimit)
                            {
                                prefabPool._despawned.Add(inst);
                                if (inst.parent != transform)
                                {
                                    inst.SetParent(transform);
                                }
                                if (inst.localScale != prefabPool.prefabScale)
                                {
                                    inst.localScale = prefabPool.prefabScale;
                                }
                                inst.gameObject.SetActive(false);
                            }
                            else
                            {
                                Destroy(inst.gameObject);
                            }
                        }
                        else
                        {
                            prefabPool._despawned.Add(inst);
                            if (inst.parent != transform)
                            {
                                inst.SetParent(transform);
                            }
                            if (inst.localScale != prefabPool.prefabScale)
                            {
                                inst.localScale = prefabPool.prefabScale;
                            }
                            inst.gameObject.SetActive(false);
                        }

                        prefabPool._spawned.Remove(inst);
                    }
                }

                break;
            }
        }
        if (inst == null) return;

        _spawned.Remove(inst);
    }

    /// <summary>
    /// 销毁对象,销毁最不常用的对象
    /// </summary>
    /// <param name="prefabName">对象名字</param>
    public void Despawn(string prefabName)
    {
        Transform inst = null;

        for (int i = 0; i < _prefabPools.Count; i++)
        {
            PrefabPool prefabPool = _prefabPools[i];
            if (prefabPool.prefab.name == prefabName)
            {
                if (prefabPool._spawned.Count > 0)
                {
                    inst = prefabPool._spawned[0];
                    if (inst)
                    {
                        if (prefabPool.despawnMaxLimit != 0)
                        {
                            if (prefabPool._despawned.Count < prefabPool.despawnMaxLimit)
                            {
                                prefabPool._despawned.Add(inst);
                                if (inst.parent != transform)
                                {
                                    inst.SetParent(transform);
                                }
                                if (inst.localScale != prefabPool.prefabScale)
                                {
                                    inst.localScale = prefabPool.prefabScale;
                                }
                                inst.gameObject.SetActive(false);
                            }
                            else
                            {
                                Destroy(inst.gameObject);
                            }
                        }
                        else
                        {
                            prefabPool._despawned.Add(inst);
                            if (inst.parent != transform)
                            {
                                inst.SetParent(transform);
                            }
                            if (inst.localScale != prefabPool.prefabScale)
                            {
                                inst.localScale = prefabPool.prefabScale;
                            }
                            inst.gameObject.SetActive(false);
                        }

                        prefabPool._spawned.Remove(inst);
                    }
                }

                break;
            }
        }
        if (inst == null) return;

        _spawned.Remove(inst);
    }

    /// <summary>
    /// 自动销毁对象
    /// </summary>
    /// <param name="inst"></param>
    /// <param name="autoDespawnTime"></param>
    /// <returns></returns>
    private IEnumerator AutoDespawn(Transform inst, float autoDespawnTime)
    {
        yield return new WaitForSeconds(autoDespawnTime);
        Despawn(inst);
    }

    /// <summary>
    /// 自动整理销毁对象列表
    /// </summary>
    /// <param name="prefabPool"></param>
    /// <returns></returns>
    private IEnumerator TidyDespawn(PrefabPool prefabPool)
    {
        yield return new WaitForSeconds(prefabPool.tidyDespawnTime);
        for (int i = 0; i < prefabPool.tidyCount; i++)
        {
            if (prefabPool._despawned.Count > prefabPool.tidyDespawnMinCount)
            {
                if (prefabPool._despawned[0])
                {
                    Destroy(prefabPool._despawned[0].gameObject);
                    prefabPool._despawned.RemoveAt(0);
                }
            }
            else
            {
                break;
            }
        }

        StartCoroutine(TidyDespawn(prefabPool));
    }

    /// <summary>
    /// 销毁所有对象
    /// </summary>
    public void DespawnAll()
    {
        for (int i = 0; i < _prefabPools.Count; i++)
        {
            PrefabPool prefabPool = _prefabPools[i];
            for (int j = 0; j < prefabPool._spawned.Count; j++)
            {
                Transform inst = prefabPool._spawned[j];
                if (inst)
                {
                    prefabPool._despawned.Add(inst);
                    if (inst.parent != transform)
                    {
                        inst.SetParent(transform);
                    }
                    if (inst.localScale != prefabPool.prefabScale)
                    {
                        inst.localScale = prefabPool.prefabScale;
                    }
                    inst.gameObject.SetActive(false);
                }
            }
            prefabPool._spawned.Clear();
        }
        _spawned.Clear();
    }

    /// <summary>
    /// 清空所有对象
    /// </summary>
    public void Clean()
    {
        StopAllCoroutines();
        for (int i = 0; i < _prefabPools.Count; i++)
        {
            PrefabPool prefabPool = _prefabPools[i];
            for (int j = 0; j < prefabPool._spawned.Count; j++)
            {
                Transform inst = prefabPool._spawned[j];
                if (inst)
                {
                    Destroy(inst.gameObject);
                }
            }
            prefabPool._spawned.Clear();

            for (int j = 0; j < prefabPool._despawned.Count; j++)
            {
                Transform inst = prefabPool._despawned[j];
                if (inst)
                {
                    Destroy(inst.gameObject);
                }
            }
            prefabPool._despawned.Clear();
        }
        _spawned.Clear();
    }

    #endregion
}

[System.Serializable]
public class PrefabPool
{
    public Transform prefab;//对象池对象
    public int initDespawnCount;//初始化数量
    public int spawnMaxLimit;//生成最多限制数量
    public float autoDespawnTime;//自动销毁时间,单位秒
    public int despawnMaxLimit;//销毁对象列表最多限制数量
    public float tidyDespawnTime;//自动整理销毁对象时间频率,单位秒
    public int tidyDespawnMinCount;//自动整理销毁对象列表最少限制数量
    public int tidyCount; //每次整理销毁对象数量

    [HideInInspector]
    public Vector3 prefabScale;//预设原大小,用于返回对象池重置大小

    public PrefabPool(){ }
    /// <summary>
    /// 初始化对象池
    /// </summary>
    /// <param name="prefab">对象</param>
    /// <param name="initDespawnCount">初始化隐藏的对象</param>
    /// <param name="spawnMaxLimit">生成最多限制数量</param>
    /// <param name="autoDespawnTime">自动销毁时间,单位秒</param>
    /// <param name="despawnMaxLimit">销毁对象列表最多限制数量</param>
    /// <param name="tidyDespawnTime">自动整理销毁对象时间频率,单位秒</param>
    /// <param name="despawnMinLimit">自动整理销毁对象列表最少限制数量</param>
    /// <param name="tidyCount">每次整理销毁对象数量</param>
    public PrefabPool(Transform prefab, int initDespawnCount = 0, int spawnMaxLimit = 0, float autoDespawnTime = 0, int despawnMaxLimit = 0,
        float tidyDespawnTime = 0, int despawnMinLimit = 0, int tidyCount = 0)
    {
        this.prefab = prefab;
        this.initDespawnCount = initDespawnCount;
        this.spawnMaxLimit = spawnMaxLimit;
        this.autoDespawnTime = autoDespawnTime;
        this.despawnMaxLimit = despawnMaxLimit;
        this.tidyDespawnTime = tidyDespawnTime;
        this.tidyDespawnMinCount = despawnMinLimit;
        this.tidyCount = tidyCount;
    }

    /// <summary>
    /// 生成的对象
    /// </summary>
    public List<Transform> _spawned = new List<Transform>();
    /// <summary>
    /// 销毁生成的对象
    /// </summary>
    public List<Transform> _despawned = new List<Transform>();
}

使用方式:

        ResManager.Load("GameObjects", "PoolItem", (go) => {
            if (PoolManager.CreatePool("Test"))
            {
                GameObject tr = go as GameObject;
                item = tr.transform;
                spawnPool = PoolManager.GetSpawnPool("Test");
                PrefabPool prefabPool = new PrefabPool(item, 10, 12, 0, 20, 5, 4, 3);
                spawnPool.AddPrefab(prefabPool);
            }
        });

猜你喜欢

转载自blog.csdn.net/yye4520/article/details/89147558