你都学会栈和队列了赶紧手搓一个对象池吧!!!(超详细,超简单适合新手宝宝学习)

前置知识:en造数据结构与算法C# 用数组实现个栈还不简单???看我一秒破之!!!(unity演示)-CSDN博客

c#有官方造好的关于stack的轮子,建议学习学习拿来直接用 

本节实现目标:(注意右侧的Cube数量没有增加而是循环激活和失活)

1.对象池详解

        对象池是一种优化游戏性能的技术,特别适用于需要频繁创建和销毁对象的场景,比如子弹、敌人、特效等。在Unity中,对象池可以显著减少内存分配和垃圾回收的开销,从而提高游戏的运行效率

 流程图解:对象池的基本原理无非就三个步骤:创建指定数量的物体,调用物体(激活%拿出),释放物体(失活&放回),之后就是激活&拿出和失活&放回之间的循环

内存图解:因为对象池就像是一个定长数组一样,所以内存是一连串而非碎片化的

对象状态图解:传统创造和销毁物体后,需要新的物体就要再创建

对象池是把需要销毁的物体重新放回池子里

2.代码详解 

之所以全部拿过来了,是因为我注释写的巨详细,直接看下去会很连贯

using System.Collections.Generic;
using UnityEngine;

public class MyPool {
    //stack作为对象池容器
    private Stack<GameObject> pool;
    //玩家可能需要调用的预制体
    private GameObject prefab;

    //像对象池创建预制体prefab和指定的数量initialCapacity
    public MyPool(GameObject prefab, int initialCapacity) {

        this.prefab = prefab;
        //实例化容器对象
        pool = new Stack<GameObject>(initialCapacity);
    
        for (int i = 0; i < initialCapacity; i++) {
            //存储实例化物体
            GameObject obj = GameObject.Instantiate(prefab);
            //失活
            obj.SetActive(false);
            //压栈
            pool.Push(obj);
        }
    }

    //玩家调用物体
    public GameObject Get() {
        //保险判断,如果对象池中有可用对象就弹栈返回出该对象
        if (pool.Count > 0) {
            return pool.Pop();
        }
        //如果没有的话,就创建并失活并返回
        else {
         
            GameObject obj = GameObject.Instantiate(prefab);
            obj.SetActive(false);//这里可以改成ture

            //至于为什么不压栈了,因为直接创建直接返回出去就得了,再压栈就还需要再弹栈,代码就重复了
            // pool.Push(obj); 如果有这行
            //return pool.Pop(); 那么得有这行
            return obj;
        }
    }
    //释放物体
    public void Release(GameObject obj) {
        //失活
        obj.SetActive(false);

        pool.Push(obj);
    }
}

3.使用示例

using System.Collections;
using UnityEngine;

public class UsePool : MonoBehaviour {
    //我用来演示的方块预制体
    public GameObject cubePrefab;
    //对象池对象
    private MyPool myPool;

    void Start() {
        //向对象池放东西
        myPool = new MyPool(cubePrefab, 10);
    }

    void Update() {
        //通过旧输入系统,按下空格就使用对象池的调用物体方法
        if (Input.GetKeyDown(KeyCode.Space)) {
            GameObject obj = myPool.Get();
            obj.transform.position = Random.insideUnitSphere * 5; // 随机位置
            obj.SetActive(true);//如果你的get方法里面obj.SetActive(false);改成ture了,就不需要这行代码了

            StartCoroutine(AutoRelease(obj, 2f)); // 启动协程,2秒后自动释放
        }
    }

    private IEnumerator AutoRelease(GameObject obj, float delay) {
        //注意是先等两秒再释放,第一次调用直接释放会出现空引用或者其他有意思的情况,你可以复制下来自己试试
        yield return new WaitForSeconds(delay);
        myPool.Release(obj);
    }
}

 4.一个小细节(重要)

在第二个大标题,也就是MyPool代码中的Get方法中,有一处可以改成ture

那么我为什么还要在UsePool类中添加这行

 是因为,你传进来的是一个预制体,难免预制体上会挂在脚本,或者像我一样在UsePool类中的Update里面写一些逻辑

如果你在Get中激活了,那么我的逻辑赶不上你激活的速度,就会发生意想不到事情

  • 20
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值