设计模式-对象池技术

对象池

       顾名思义,对象池是存放对象的缓冲区。用户可以从缓冲区中放入/取出对象。一类对象池存放一类特定的对象。那么对象池有什么用呢?在游戏中,经常会有产生/销毁大量同类游戏对象的需求,比如游戏中源源不断的敌人、频繁刷新的宝箱、乃至一些游戏特效(风、雨等)。如果没有一种比较好的机制来管理这些对象的产生和销毁,而是一昧的Instantiate和Destroy,将使你的游戏性能大大下降,甚至出现卡死、崩溃…
      简而言之,就是当需要使用一个对象的时候,直接从该类对象的对象池中取出(SetActive(true)),如果对象池中无可用对象,再进行Instantitate。而当不再需要该对象时,不直接进行Destroy,而是SetActive(false)并将其回收到对象池中。
      搜,这个时候对象池该上场了
(1)简易版
     这里我使用到的是字典键值对的方式进行存储、当然还有堆栈的方式。大家可以去其他博客进行参考

//==========================
// - FileName:      PrefabTool.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 22:49:01	
// - Email:         [email protected]		
// - Region:        China WUHAN	
// - Description:   
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PrefabTool
{
    //通过单例拿到对象池
    private static PrefabTool _ins;
    public static PrefabTool Getins()
    {
        if (_ins==null)
        {
            _ins = new PrefabTool();
        }
        return _ins;
    }
    
    /// <summary>
    /// 1、加载预制件
    /// 2、把加载完成的预制件放在对象池
    /// 3、预制件不会删除,将预制件重用
    ///</summary>

    //1、生成一个存储对象预制件的库,使用字典:键值对
    Dictionary<string, GameObject> prefadic = new Dictionary<string, GameObject>();

    //2、用一个泛型集合List存储所有的对象
    Dictionary<string, List<GameObject>> objDic = new Dictionary<string, List<GameObject>>();

    //加载预制件
    public GameObject LoadPre(string Path)
    {
        //判断对象池中是否有对象
        if (!prefadic.ContainsKey(Path))
        {
            //如果没有对象就把对象加载到池子中
            GameObject preObj = Resources.Load<GameObject>(Path);
            //通过地址添加预制体
            prefadic.Add(Path, preObj);
        }
        //如果有的话就直接使用
        GameObject obj = prefadic[Path];
        //返回一个预制体对象
        return obj;
    }

    //用来存储预制体对象
    public GameObject GetInsObj(string Path)
    {
        //如果没有根据键查找到对象的话
        if (!prefadic.ContainsKey(Path))
        {
            objDic.Add(Path, new List<GameObject>());
        }
        //将预制体的地址存到一个泛型集合中
        List<GameObject> insit = objDic[Path];
        //如果集合中没有元素
        if (insit.Count == 0) 
        {
            //加载
            GameObject preobjObj = LoadPre(Path);
            insit.Add(GameObject.Instantiate<GameObject>(preobjObj));
        }
        GameObject game = insit[insit.Count - 1];
        //删除集合中的最后一个
        insit.Remove(game);
        //返回游戏对象
        return game;
    }

    //回收游戏对象
    public void Remove(string Path,GameObject obj)
    {
        if (objDic.ContainsKey(Path))
        {
            objDic[Path].Add(obj);
        }
        else
        {
            Debug.Log("键值错误.....");
        }
    }
}

另外就是通过一个路径(静态类、使用const常量进行修饰)来进行存储:

//==========================
// - FileName:      PrefabConst.cs         
// - Created:       true.	
// - CreateTime:    2020/02/27 22:48:01	
// - Email:         [email protected]		
// - Region:        China WUHAN	
// - Description:   
//==========================
public static class PrefabConst
{
    //预制件路径
    public const string bullet = "**";
}

(2)使用堆栈就行制作对象池、升级版

//==========================
// - FileName:      ObjectTool.cs         
// - Created:       true.	
// - CreateTime:    2020/03/02 21:40:47	
// - Email:         [email protected]		
// - Region:        China WUHAN	
// - Description:   使用堆栈实现对象池技术
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectTool : MonoBehaviour
{
    
    //获取资源
    public GameObject monster;
    //游戏物体对象池
    private Stack<GameObject> monsterPool;
    //激活游戏物体的列表
    private Stack<GameObject> activeList;

    void Start()
    {
        monsterPool = new Stack<GameObject>();
        activeList = new Stack<GameObject>();
    }
    
    //取得游戏物体
    private GameObject GetMonster()
    {
        GameObject monsterGo = null;
        //是否有游戏物体
        if (monsterPool.Count <= 0) 
        {
            //生成物体
            monsterGo = Instantiate(monster);
        }
        else
        {
            //弹出栈
            monsterGo = monsterPool.Pop();
            //激活
            monsterGo.SetActive(true);
        }
        return monsterGo;
    }

    //压栈、放回对象池
    private void PushMonster(GameObject monsterGo)
    {
        //设置父对象
        monsterGo.transform.SetParent(transform);
        //禁用游戏物体
        monsterGo.SetActive(false);
        //压栈
        monsterPool.Push(monsterGo);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            //从池子中取得游戏物体
            GameObject go = GetMonster();
            go.transform.position = Vector3.one;
            //讲拿到的物体放到怪物列表中
            activeList.Push(go);
        }
        else if (Input.GetKeyDown(KeyCode.D))
        {
            //判断激活列表是否有元素
            if (activeList.Count >= 0)
            {
                PushMonster(activeList.Pop());
            }
        }
    }

}

发布了29 篇原创文章 · 获赞 2 · 访问量 786

猜你喜欢

转载自blog.csdn.net/zhanxxiao/article/details/104546674