Unity基础小框架(二):对象池(缓存池)模块

8 篇文章 0 订阅
6 篇文章 0 订阅

使用对象池能够重复利用创建的资源,避免重复的创建和销毁,减少内存分配和垃圾回收带来的开销。当某个物品需要重复的创建和销毁时,就可以考虑用到对象池。

核心需要两样

  1. 存放不同对象池的一个容器,Dictionary
  2. 存放物体的对象池,List、Stack、Queue等等

是否设置构造函数为私有取决于继承的单例模板的实现方式,使用单例模式是为了确保该类具有唯一的实例,并能够通过获取实例的方法直接调用对象池模块里的内容。

在存取对象时,是否激活或者隐藏物体取决于具体的设计,还可以采用将物体移动到某个位置等方法。

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

public class PoolData
{
    public GameObject father;
    public Stack<GameObject> poolStack;

    public PoolData(GameObject obj, GameObject poolFather)
    {
        father = new GameObject(obj.name);
        father.transform.parent = poolFather.transform;
        poolStack = new Stack<GameObject>();
        PushObj(obj);
    }

    public void PushObj(GameObject obj)
    {
        obj.SetActive(false);
        poolStack.Push(obj);
        obj.transform.SetParent(father.transform);
    }

    public GameObject GetObj()
    {
        GameObject obj = poolStack.Pop();
        obj.SetActive(true);
        obj.transform.parent = null;
        return obj;
    }
}


public class PoolManager : BaseManger<PoolManager>
{
    //作为储存不同类型对象池的容器
    private Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();
    private PoolManager() { }

    private GameObject poolObj;
    /// <summary>
    /// 获取一个物体
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public GameObject GetObj(string name)
    {
        GameObject obj = null;
        try
        {
            //判断该类型池是否存在,并且池中是否有物体
            if (poolDic.ContainsKey(name) && poolDic[name].poolStack.Count > 0)
            {
                obj = poolDic[name].GetObj();
            }
            else
            {
                //不存在就直接从资源里加载并在场景生成一个物体
                obj = Instantiate(Resources.Load<GameObject>(name));
                obj.name = name;    //去掉(clone)后缀
            }
        }
        catch(Exception e)
        {
            Debug.LogError("资源获取失败:" + e.Message);
        }
        return obj;
    }

    /// <summary>
    /// 将物体放入对象池
    /// </summary>
    /// <param name="name"></param>
    /// <param name="obj"></param>
    public void PushObj(string name, GameObject obj)
    {
        if (poolObj is null)
        {
            poolObj = new GameObject("Pool");
        }

        if (poolDic.ContainsKey(name))
        {
            poolDic[name].PushObj(obj);
        }
        else
        {
            poolDic.Add(name, new PoolData(obj, poolObj));
        }
    }

    /// <summary>
    /// 清空全部池
    /// </summary>
    public void ClearAllPool()
    {
        poolDic.Clear();
        poolObj = null;
    }
}

如果想要异步加载资源,则做如下修改

资源管理器模块

    public void GetObj(string name, UnityAction<GameObject> callback)
    {
        try
        {
            //判断该类型池是否存在,并且池中是否有物体
            if (poolDic.ContainsKey(name) && poolDic[name].poolStack.Count > 0)
            {
                callback(poolDic[name].GetObj());
            }
            else
            {
                ResManager.GetInstance().LoadAsync<GameObject>(name, callback);
            }
        }
        catch(Exception e)
        {
            Debug.LogError("资源获取失败:" + e.Message);
        }        
    }

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,这是一个比较复杂的问题,需要分步骤来回答。首先,我们需要明确几个概念: 1. 对象池:是一种重复利用已创建对象的技术,可以有效减少对象的创建和销毁所带来的性能开销。 2. 协程:是一种轻量级线程,可以在主线程外执行一些较为耗时的操作,比如延时、等待、动画等。 在Unity中,我们可以通过编写脚本来实现对象池的管理和协程的使用。下面是一个简单的示例代码: ```csharp using System.Collections; using System.Collections.Generic; using UnityEngine; public class ObjectPool : MonoBehaviour { public GameObject prefab; // 预制体 public int initCount; // 初始数量 public int maxCount; // 最大数量 private List<GameObject> pool; // 对象池 private Queue<int> queue; // 空闲索引队列 private void Awake() { pool = new List<GameObject>(); queue = new Queue<int>(); // 初始化对象池 for (int i = 0; i < initCount; i++) { GameObject obj = Instantiate(prefab, transform); obj.SetActive(false); pool.Add(obj); queue.Enqueue(i); } } private void Update() { // 从对象池中获取一个对象 GameObject obj = GetObject(); if (obj != null) { // 激活对象 obj.SetActive(true); // 启动协程 StartCoroutine(WaitAndDeactivate(obj)); } } private GameObject GetObject() { if (queue.Count > 0) { // 从空闲索引队列中取出一个索引 int index = queue.Dequeue(); // 返回对应的对象 return pool[index]; } else if (pool.Count < maxCount) { // 创建新的对象 GameObject obj = Instantiate(prefab, transform); obj.SetActive(false); pool.Add(obj); // 返回新创建的对象 return obj; } else { // 对象池已满,返回null return null; } } private IEnumerator WaitAndDeactivate(GameObject obj) { yield return new WaitForSeconds(1.0f); obj.SetActive(false); // 将索引重新加入空闲索引队列中 int index = pool.IndexOf(obj); queue.Enqueue(index); } } ``` 这个脚本实现了一个简单的对象池,可以重复利用预制体来减少对象的创建和销毁。在Update()方法中,我们从对象池中获取一个对象,然后通过调用SetActive()方法将其激活,并启动一个协程来等待一定时间后再将其隐藏。在WaitAndDeactivate()方法中,我们通过调用yield return new WaitForSeconds()来等待一定时间,然后将对象隐藏,并将其索引重新加入空闲索引队列中,以便下次可以重复利用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值