Unity简易对象池管理器

Unity 对象池

在做游戏开发的时候我们通常会遇到一种情况,就是某个对象使用的频率非常高,但是很快又将销毁。比如在射击游戏中的子弹,一个玩家在短时间内可以发射很多的子弹,但是子弹的生命周期却是非常的短暂。如果频繁的使用Instantiate Destroy进行控制,势必会导致游戏的性能下降,并且在频繁生成销毁过程中也会导致生成大量的内存碎片,不利于游戏的整体性能。

对象池顾名思义是用来存储对象的池子,在我们需要某个对象的时候,可以直接从对象池中取出来,不用的时候在放回池子中,避免了频繁的创建对象和销毁对象带来的性能影响。

实现思路

由于在一个项目中可能存在多个不用类型的对象池子,所以采用GoPManager来管理多个类型的池子。并且定义PoolType来存放池子的基本信息,然后池子信息需要在GoPManager中进行注册Register。在注册池子信息给我们的GoPManager之后,程序可以在任何地方创建我们已经注册的池子CreatePool,在创建池子之后,池子中所有的对象默认处于未激活状态,并且默认挂在在GoPManager的附加物体上,可以运行游戏进行查看。

在管理不同类型的池子采用Dictionary进行管理,键为池子对应的Prefab。同一个池子中的对象管理采用Queue进行管理,使用时取出队列头部对象,使用完毕回收至队列尾部。

使用流程

  1. 实例化一个GoPManager对象
  2. 注册PoolType信息到GoPManager
  3. 创建对象池CreatePool
  4. 生成对象Spawn
  5. 使用……
  6. 回收对象Recycle

实现效果

img

Demo

新建一个游戏对象,并且添加一个控制脚本PoolManager

image-20200418235635276

在脚本中实例化GopManager,注册并创建出对象池中的对象

public class PoolManager : MonoBehaviour
{
    public List<GoPManager.PoolType> pools = new List<GoPManager.PoolType>();
    public GoPManager poolManager;
    private void Awake()
    {
        poolManager = new GoPManager(gameObject);
        poolManager.Register(pools);
        foreach (var item in pools)
            poolManager.CreatePool(item.prefab);
    }
}

此时运行我们游戏,可以看出我们注册的对象池已经创建完毕

image-20200419094622694

在使用时我们在玩家的开火代码中进行控制,原本的GameObject.Instantiate更换为GoPManager.Spawn即可。在对象使用完毕时使用GoPManager.Recycle进行对象的回收。

public class PlayerFire : MonoBehaviour
{
    public GameObject m_shell;
    public Transform m_firePosition;
    GoPManager pManager;
    private void Start()
    {
        pManager = FindObjectOfType<PoolManager>().poolManager;
    }
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            GameObject go = pManager.Spawn(m_shell, m_firePosition.position, m_firePosition.rotation);
            go.GetComponent<Rigidbody>().velocity = m_firePosition.forward * 10f;
            StartCoroutine(Recycle(go, 1f));
        }
    }
    IEnumerator Recycle(GameObject obj,float t)
    {
        yield return new WaitForSeconds(t);
        pManager.Recycle(m_shell, obj);
    }
}

项目地址

项目地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这里给出一个比较完整的Unity对象池管理脚本示例: ```csharp using System.Collections; using System.Collections.Generic; using UnityEngine; public class ObjectPool : MonoBehaviour { [SerializeField] private GameObject prefab; // 预制体 [SerializeField] private int initCount; // 初始数量 [SerializeField] private 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); } } // 从对象池中获取一个对象 public 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; } } // 将对象重新加入对象池中 public void ReleaseObject(GameObject obj) { // 将对象隐藏 obj.SetActive(false); // 将索引重新加入空闲索引队列中 int index = pool.IndexOf(obj); queue.Enqueue(index); } } ``` 这个脚本实现了一个简单的对象池,可以通过调用GetObject()方法从对象池中获取一个对象,然后通过调用ReleaseObject()方法将其重新加入对象池中。在Awake()方法中,我们初始化了对象池,将初始数量的对象创建出来,并将其索引加入空闲索引队列中。在GetObject()方法中,我们从空闲索引队列中取出一个索引,然后返回对应的对象,如果对象池已满,则创建新的对象。在ReleaseObject()方法中,我们将对象隐藏,然后将其索引重新加入空闲索引队列中,以便下次可以重复利用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值