Unity | 简易对象池

目录

前言

一、对象池简介

二、实现步骤

1.新建脚本ObjectPool.cs

2.添加 获取对象 方法

3.添加 回收对象 方法

4.完整代码

三、使用方法

四、效果展示

最后


前言

仅个人学习的记录,旨在分享我的学习笔记和个人见解。 


一、对象池简介

        Unity对象池是一种用于管理和重复使用游戏对象的技术。它可以减少在游戏中频繁创建和销毁游戏对象,从而减少内存占用和提高游戏性能。通过对象池,游戏对象可以被预先创建并缓存在内存中,当需要时可以从池中获取并激活,使用完毕后则放回对象池以便下次重复利用。

二、实现步骤

1.新建脚本ObjectPool.cs

使用单例模式,通过字典的方式存储各个对象的队列。

代码如下

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

public class ObjectPool
{
    
    private static ObjectPool instance; // 单例
    private GameObject pool;// 对象池游戏物体
    private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();// 对象池字典,(string对象名字,对象队列)
    
    public static ObjectPool Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ObjectPool();
            }
            return instance;
        }
    }


}

2.添加 获取对象 方法

        先判断字典中是否包含对象队列 或 对象队列中是否有可用对象
若队列中没有可用的对象,先实例化一个对象加入对应池子中,再从对应池子中获取对象。

        为了后续便于管理,在实例化对象时,会自动在pool对象下建立 “对象名Pool”(如 子弹Pool),并在“对象名Pool”下存放被实例化的对象。

具体方法如下:

public GameObject GetObject(GameObject prefab)
    {
        GameObject _object;

        //若场景中没有ObjectPool物体,则新生成一个物体 并 新建字典。
        pool = GameObject.Find("ObjectPool");
        if (!pool) 
        {
            pool = new GameObject("ObjectPool");
            objectPool = new Dictionary<string, Queue<GameObject>>();
        }
        //如果对应池子里没有该可用对象
        if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0)
        {
            
            _object = GameObject.Instantiate(prefab);//实例化对象,加入队列
            
            PushObject(_object);//回收对象到对应池子,并设置为隐藏

            //查找ObjectPool下是否有对饮 名字的池子物体
            GameObject childPool = GameObject.Find("ObjectPool/"+prefab.name + "Pool");
            if (!childPool)
            {
                childPool = new GameObject(prefab.name + "Pool");
                childPool.transform.SetParent(pool.transform);
            }

            _object.transform.SetParent(childPool.transform);//存放到对应池子物体位置下
        }
        
        _object = objectPool[prefab.name].Dequeue();//对应池子中的对象出列。
        _object.SetActive(true);

        return _object;
    }

3.添加 回收对象 方法

        先判断字典中是否有对象名的key,若没有则新建一条数据加入字典中。再把要回收的对象加入字典里对应key值的队列中。

具体方法如下:

 public void PushObject(GameObject prefab)
    {
        string _name = prefab.name.Replace("(Clone)", string.Empty);
        //如果字典中没有对应的key值,则新建一条数据
        if (!objectPool.ContainsKey(_name))
            objectPool.Add(_name, new Queue<GameObject>());
        //对象入列
        objectPool[_name].Enqueue(prefab);
        prefab.SetActive(false);
    }

到这里,一个简单的对象池就已经搭建完成啦。


4.完整代码

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

public class ObjectPool
{
    private static ObjectPool instance; // 单例
    private GameObject pool;// 对象池游戏物体
    private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();// 对象池字典,(string对象名字,对象队列)

    public static ObjectPool Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ObjectPool();
            }
            return instance;
        }
    }
    public GameObject GetObject(GameObject prefab)
    {
        GameObject _object;

        //若场景中没有ObjectPool物体,则新生成一个物体 并 新建字典。
        pool = GameObject.Find("ObjectPool");
        if (!pool) 
        {
            pool = new GameObject("ObjectPool");
            objectPool = new Dictionary<string, Queue<GameObject>>();
        }
        //如果对应池子里没有该可用对象
        if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0)
        {
            
            _object = GameObject.Instantiate(prefab);//实例化对象,加入队列
            
            PushObject(_object);//存储对象到对应池子,并设置为隐藏

            //查找ObjectPool下是否有对饮 名字的池子物体
            GameObject childPool = GameObject.Find("ObjectPool/"+prefab.name + "Pool");
            if (!childPool)
            {
                childPool = new GameObject(prefab.name + "Pool");
                childPool.transform.SetParent(pool.transform);
            }

            _object.transform.SetParent(childPool.transform);//存放到对应池子物体位置下
        }
        
        _object = objectPool[prefab.name].Dequeue();//对应池子中的对象出列。
        _object.SetActive(true);

        return _object;
    }
    public void PushObject(GameObject prefab)
    {
        string _name = prefab.name.Replace("(Clone)", string.Empty);
        //如果字典中没有对应的key值,则新建一条数据
        if (!objectPool.ContainsKey(_name))
            objectPool.Add(_name, new Queue<GameObject>());
        //对象入列
        objectPool[_name].Enqueue(prefab);
        prefab.SetActive(false);
    }
}

三、使用方法

        例如,我想要生成“子弹”,只需要调用对象池的生成对象方法(GetObject),想要关闭“子弹”,则调用回收对象的方法(PushObject)

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;

public class Test : MonoBehaviour
{
    public GameObject bullet;//子弹预制体

    void Update()
    {
        //按下鼠标左键生成子弹
        if (Input.GetMouseButtonDown(0))
        {
            GameObject _bullet = ObjectPool.Instance.GetObject(bullet);

            //延迟2秒后回收子弹到对象池中
            float f = 0;
            DOTween.To(() => f, a => f = a, 1f, 2f).OnComplete(() =>
            {
                ObjectPool.Instance.PushObject(_bullet);
            });
           
        }
    }
}

四、效果展示


最后

        文章内容仅为个人学习记录。好记性不如烂笔头,为了能更好的回顾和总结,开始记录与分享自己学到的Unity知识。若文章内容错误,麻烦指点。

  • 19
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值