unity对象池示例

对象池,为了减小内存压力而产生的一种资源回收方式。

方式一:

下方脚本演示了一个简单的对象池的实现逻辑:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
///< summary >
/// 对象池
/// </summary>
public class GameObjectPool : MonoBehaviour
{

    //内部容器,用于存入缓存的对象
    private Dictionary<string, List<GameObject>> cache = new Dictionary<string, List<GameObject>>();

    /// <summary>
    /// 生产物体
    /// </summary>
    public GameObject CreateObject(string key, GameObject go, Vector3 position, Quaternion quaternion)
    {
        //有:key对应列表中有没有可用(非活动状态)的物体
        var tempGo = FindUsable(key);
        if (tempGo != null)
        {
            //有:设置后返回可用物体
            tempGo.transform.position = position;
            tempGo.transform.rotation = quaternion;
            tempGo.SetActive(true);
        }
        else
        {
            //没有:(场景中没有,内存中也没有)创建物体后添加cache,
            tempGo = Instantiate(go, position, quaternion) as GameObject;
            Add(key, tempGo);
        }
        return tempGo;
    }

    /// <summary>
    /// 将对象放入缓存
    /// </summary>
    private void Add(string key, GameObject newObject)
    {
        //创建key,创建key的列表
        if (!cache.ContainsKey(key))
            cache.Add(key, new List<GameObject>());
        cache[key].Add(newObject);
    }

    /// <summary>
    /// 找对应key的列表中没有没可用的物体
    /// </summary>
    private GameObject FindUsable(string key)
    {
        //有Key: 找非活动状态的物体
        if (cache.ContainsKey(key))
        {
            return cache[key].Find(p => !p.activeSelf);
        }
        return null;
    }

    /// <summary>
    /// 即时回收
    /// </summary>
    /// <param name="go">要回收的对象</param>
    public void CollectObject(GameObject go)
    {
        go.SetActive(false);
    }

    /// <summary>
    /// 延时回收
    /// </summary>
    /// <param name="go">要回收的对象</param>
    /// <param name="delay">延时时长</param>
    public void CollectObject(GameObject go, float delay)
    {
        //开启协程
        StartCoroutine(Delay(go, delay));
    }

    /// <summary>
    /// 用于回收的协程方法
    /// </summary>
    public IEnumerator Delay(GameObject go, float delay)
    {
        //等待delay之后,
        yield return new WaitForSeconds(delay);
        //调用即时回收
        CollectObject(go);
    }

    /// <summary>
    /// 将key对象的缓存物体从池中清除(销毁)
    /// </summary>
    /// <param name="key"></param>
    public void Clear(string key)
    {
        if (cache.ContainsKey(key))
        {
            while (cache[key].Count > 0)
            {
                //销毁每个物体
                Destroy(cache[key][0]);
                //删除列表中的空引用
                cache[key].RemoveAt(0);
            }
            //删除key
            cache.Remove(key);
        }
    }

    /// <summary>
    /// 清空池中物体
    /// </summary>
    public void ClearAll()
    {

        //遍历所有的key
        List<string> keys = new List<string>(cache.Keys);
        //逐个清除
        while (cache.Count > 0)
        {
            Clear(keys[0]);
            keys.RemoveAt(0);
        }
    }
}

测试效果
在这里插入图片描述

上边的例子中,所有生成的物体不会被主动销毁而是被隐藏起来,需要使用时直接显示出来,重复利用。可以满足一些常规的需求了。

方式二(用PoolManager插件)

另外你也可以使用PoolManager插件来达到这种效果
这里可以下载http://www.qudong51.net/qudong/851.html
新建节点挂这个脚本,下方可以提前添加想要实例的预制体,并提供了一些数量限制、自动销毁清理之类的选项
在这里插入图片描述
调用

	///从内存池里面取一个GameObjcet
			Transform momo = 	spawnPool.Spawn("momo");

//清空池子
using UnityEngine;
using System.Collections;
using PathologicalGames;
 
public class NewBehaviourScript : MonoBehaviour {
 
	SpawnPool spawnPool;
	PrefabPool refabPool;
	void Start()
	{
		spawnPool = PoolManager.Pools["Shapes"];
		refabPool = new PrefabPool(Resources.Load<Transform>("momo"));
	}
 
	void OnGUI()
	{
		if(GUILayout.Button("初始化内存池"))
		{
			if(!spawnPool._perPrefabPoolOptions.Contains(refabPool))
			{
				refabPool = new PrefabPool(Resources.Load<Transform>("momo"));
				//默认初始化两个Prefab
				refabPool.preloadAmount = 2;
				//开启限制
				refabPool.limitInstances = true;
				//关闭无限取Prefab
				refabPool.limitFIFO = false;
				//限制池子里最大的Prefab数量
				refabPool.limitAmount =5;
				//开启自动清理池子
				refabPool.cullDespawned = true;
				//最终保留
				refabPool.cullAbove = 10;
				//多久清理一次
				refabPool.cullDelay = 5;
				//每次清理几个
				refabPool.cullMaxPerPass =5;
				//初始化内存池
				spawnPool._perPrefabPoolOptions.Add(refabPool);
				spawnPool.CreatePrefabPool(spawnPool._perPrefabPoolOptions[spawnPool.Count]);
			}
		}
 
		if(GUILayout.Button("从内存池里面取对象"))
		{
			///从内存池里面取一个GameObjcet
			Transform momo = 	spawnPool.Spawn("momo");
		}
 
 
		if(GUILayout.Button("清空内存池"))
		{
			//清空池子
			spawnPool.DespawnAll();
		}
	}
}

这个来自雨松:https://www.xuanyusong.com/archives/2974

using UnityEngine;
using System.Collections;
using PathologicalGames;
public class AssembleModel : MonoBehaviour
{
    //创建
    public Transform Spawner(string prefabs, string names = "", string SpawnPools = "prefabs")
    {
        Transform inst;
        SpawnPool shapesPool = PoolManager.Pools[SpawnPools];
        inst = shapesPool.Spawn(Resources.Load<Transform>(prefabs));
         if (names == "")
             names = prefabs + Time.timeScale;
         inst.name = names;
        return inst;
    }

    //全体删除
    public void Despawner(string SpawnPools = "prefabs")
    {
        SpawnPool shapesPool = PoolManager.Pools[SpawnPools];
        shapesPool.DespawnAll();
    }
    //单个删除 
    public void Despawn(Transform transform, string SpawnPools = "prefabs")
    {
        SpawnPool shapesPool = PoolManager.Pools[SpawnPools];

        shapesPool.Despawn(transform);
    }
}

↑这个来自博客园用户“太粗难进”:https://www.cnblogs.com/big-zhou/p/4135380.html

posted @ 2022-06-22 18:05  哒哒哒~~~  阅读(83)  评论(0编辑  收藏  举报