牛骨文教育服务平台(让学习变的简单)
博文笔记

Unity3D开发之对象池

创建时间:2018-04-08 投稿人: 浏览次数:156

    在做UI的下拉列表和游戏中物体的实例化时,我们经常会用到对象池。因为对象池会把生成的物体回收起来供下次使用,节省很大的性能。

    项目中通常会有多个不同类型的预制体需要被大量复制,所以我们首先要创建一个子池来产生不同类型的预制体,然后在创建一个大池子来存储管理所有被实例化的不同类型的预制体。首先来完成我们的子池脚本:

public class SubPool{
   
    private List<GameObject> objects=new List<GameObject>();

    private GameObject prefab;

    private Transform parent;

    public string Name { get { return prefab.name; } }

    public SubPool(Transform parent,GameObject go)
    {
        this.prefab = go;
        this.parent = parent;
    }
    //取出物体
    public GameObject Spawn()
    {
        GameObject go = null;
        for (int i = 0; i < objects.Count; i++)
        {
            if (!objects[i].activeSelf)
            {
                go = objects[i];
            }
        }
        if (go == null)
        {
            go = GameObject.Instantiate<GameObject>(prefab);
            go.transform.SetParent(parent);
            objects.Add(go);
        }
        go.SetActive(true);
        return go;
    }

    //回收物体
    public void UnSpawn(GameObject go)
    {
        if (objects.Contains(go))
        {
            go.SetActive(false);
        }
    }
    //回收所有物体
    public void UnSpawnAll()
    {
        for (int i = 0; i < objects.Count; i++)
        {
            UnSpawn(objects[i]);
        }
    }

    public bool Contain(GameObject go)
    {
        return objects.Contains(go);
    }
}

    然后在创建一个大池子来管理这些被实例化的物体:

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

public class ObjectPool : MonoSingleton<ObjectPool>
{
    /// <summary>
    /// 资源目录
    /// </summary>
    public string ResourceDir = "Pool";

    Dictionary<string,SubPool> pools=new Dictionary<string, SubPool>();
    
    //取出物体
    public GameObject Spawn(string name,Transform trans)
    {
        SubPool subPool = null;
        if (!pools.ContainsKey(name))
            CreatNewsubPool(name,trans);

        subPool = pools[name];
        return subPool.Spawn();
    }
    //回收物体
    public void UnSpawn(GameObject go)
    {
        SubPool pool = null;
        foreach (var p in pools.Values)
        {
            if (p.Contain(go))
            {
                pool = p;
                break;
            }
        }
        pool.UnSpawn(go);
    }

   // 回收所有物体
    public void UnSpawnAll()
    {
        foreach (var p in pools.Values)
        {
            p.UnSpawnAll();
        }
    }

    //新建一个池子
    private void CreatNewsubPool(string name,Transform parent)
    {
        string path = ResourceDir + "/" + name;

        GameObject go = (Resources.Load<GameObject>(path));

        SubPool pool=new SubPool(parent,go);
        pools.Add(name, pool);
    }
}

ObjectPool是单利模式,我们获取的时候直接全局获取来控制。在使用对象池取物体时,我们调用Spawn函数并传入预制体的名字以及对象池里的物体要放到的父物体下,通常我们在调用之前一般会将之前的隐藏,比如刷新列表重新载入数据。代码如下:

//先全部回收
        for (int i = 0; i<ParentTransform.childCount; i++)
        {
            ObjectPool.Instance.UnSpawn(ParentTransform.GetChild(i).gameObject);
        }
            //然后在取出
            Debug.Log(roomDatas.Count);
        for (int i = 0; i<roomDatas.Count; i++)
        {
            GameObject cloneGo = ObjectPool.Instance.Spawn("Item", ParentTransform);
            cloneGo.transform.SetAsLastSibling();//开发刷新列表的时候我们会发现从池子里取出物体的顺序不对  我们要设置按照数据顺序显示
            //cloneGo.GetComponent<Item>().Init(i, roomDatas[i],this);
        }

    以上是我在项目中遇到的对象池使用问题。

    如果本博客对你有帮助,记得点关注哦!


声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。