Unity对象池

本文介绍了Unity中的对象池技术,用于优化CPU性能,避免频繁创建和销毁游戏对象。对象池通过存储和复用游戏对象,减少了内存分配和垃圾收集的开销。文中提供了一个具体的实现示例,包括对象池类的设计,如查找、添加、释放和回收对象的方法。并通过测试场景展示了对象池如何工作,确保游戏物体在回收后能够重新启用,从而提高游戏性能。
摘要由CSDN通过智能技术生成

对象池

主要是CPU优化方面

概念:

对象池顾名思义 ,它能存储很多对象,应用于处理需要大量重复利用的资源的,我们每次都是创建销毁创建销毁,这是很耗计算机性能的,我们完全可以把不用的资源暂时禁用掉而不是销毁,当我们需要再次使用时就把它激活重复利用。

生活案例:

我个人更喜欢举生活中的例子来学习,比如生活中我们吃饭通常都是用筷子,我们需要的游戏物体就和一次性筷子一样,用完就一般人不会再用第二遍直接扔掉,但是如果我们使用的是非一次性筷子,每当我们使用完便可以将它洗干净放入刀具架上,当我们需要的时候,就去取,当家里人多几双筷子不能满足我们的需求,我们可以买新筷子加入到刀具架上,有需就从刀具架上取。

原理:

对象池的原理很简单,就是首先我们需要一个池子,可以用字典等,使用什么来存储,取决于你的数据结构学习程度,没有最好的的方法,只有你还没想到的方法,再就需要一个从池子中取东西的方法和回收到池子中的方法和释放资源的方法,回收就是暂时不用的资源我们将其禁用掉,释放资源则是在池子中彻底删除掉该资源。

实现:

注:本例继承了SingleCase类,游戏对象池在游戏中最好只有一个,所以将它设计为单例模式。

SingleCase类:在这里

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

///<summary>
///对象池
///</summary>
public class ObjectPool : SingleCase<ObjectPool>
{
    private ObjectPool() { }
    //1.创建池:用来存放对象   key:想应的Key值
    private Dictionary<string, List<GameObject>> dir = 
        new Dictionary<string, List<GameObject>>();
    //2.创建使用池的元素【游戏对象】一个对象并使用对象:
    //池中有从池中返回;池中如果没有所需的对象则加载一个新的对象,放入池中再返回
    /// <summary>
    /// 创建对象
    /// </summary>
    /// <param name="key">要生成对象对应的key值</param>
    /// <param name="gameObj">游戏对象</param>
    /// <param name="position">生成位置</param>
    /// <param name="quaternion">生成角度</param>
    /// <returns>返回生成游戏对象</returns>
    public GameObject CreateObject(string key,GameObject gameObj,Vector3 position, Quaternion quaternion)
    {
        //1)查找池中有无可用的游戏对象
        GameObject gameObject = FindPoolKey(key);
        //2)池中有对象从池中返回
        if(gameObject != null)
        {   //对象池中有可用 赋给对象位置
            gameObject.transform.position = position;//生成位置
            gameObject.transform.rotation = quaternion;//生成角度
            gameObject.SetActive(true);//启用当前游戏对象
        }
        else//3)池中没有加载,放入池中再返回
        {   //实例化生成游戏物体
            gameObject = Instantiate(gameObj, position, quaternion);
            Add(key,gameObject);//放入池中
        }
        gameObject.transform.parent = transform;//调整到父物体下
        return gameObject;
    }

    /// <summary>
    /// 查找Key方法
    /// </summary>
    /// <param name="key">当前游戏物体Key值</param>
    /// <returns>返回当前对象池中存在的空闲游戏物体,不存在则返回空</returns>
    private GameObject FindPoolKey(string key)
    {   //查找当前对象池中是否有该游戏物体所对应的列表
        if (dir.ContainsKey(key))
        {   //找列表  中找出 未激活【空闲】的游戏物体
            return dir[key].Find(p => !p.activeSelf);
        }
        return null;
    }

    /// <summary>
    /// 加入池列表
    /// </summary>
    /// <param name="key">当前游戏物体对应的Key值</param>
    /// <param name="gameObject">当前游戏物体类型</param>
    private void Add(string key,GameObject gameObject)
    {   //如果该池未曾初始化  当前游戏物体的key  初始化
        if (!dir.ContainsKey(key))
        {
            dir.Add(key, new List<GameObject>());
        }
        //加入到属于当前游戏物体的列表中
        dir[key].Add(gameObject);
    }

    //释放资源:从池中删除对象
    //释放部分:按Key释放
    public void Clear(string key)
    {   //判断当前Key值是否存在与池中
        if (dir.ContainsKey(key))
        {   //循环 把列表中所有的游戏物体删除
            for(int i = 0; i < dir[key].Count; i++)
            {
                Destroy(dir[key][i]);
            }
            dir.Remove(key);//移除了在池中对象的地址
        }
    }

    //释放全部 循环调用Clear
    public void ClearAll()
    {   //存池中所有的Key值
        List<string> list = new List<string>(dir.Keys);
        //遍历 调用删除单一Key值的方法
        for(int i = 0; i < dir.Keys.Count; i++)
        {
            Clear(list[i]);
        }
    }

    //回收对象:使用完对象返回池中【从画面中消失】
    //即时回收对象
    public void CollectObject(GameObject go)
    {
        go.SetActive(false);//禁用游戏物体
    }

    //延时回收对象
    public void CollectObject(GameObject go,float delay)
    {   //开启携程
        StartCoroutine(CollectDelay(go, delay));
    }
    private IEnumerator CollectDelay(GameObject go, float delay)
    {   //等待delay时间调用回收方法
        yield return new WaitForSeconds(delay);
        CollectObject(go);
    }
}

测试:

创建两个预制体Cube,Sphere(通过窗口拖拽赋值)

通过OnGUI创建两个按钮,当点击在一定范围内随机创建一个存在两秒的游戏物体。

目标:

观察游戏物体在Hierarchy 窗口视图,是否按预期当游戏物体被回收掉,再次点击按钮是否从池中启用禁用的游戏物体。

using System.Collections;
using UnityEngine;
/// <summary>
/// 测试方法
/// </summary>
public class Test : MonoBehaviour
{
    public GameObject[] pre;//要生成对象的预制体
    public string[] keys = {"cube","sphere" };//对应对象的Key值
    ObjectPool pool;//对象池

    void Start()
    {   //初始化对象池
        pool = ObjectPool.Instance;
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(100, 100, 300, 300), "创建Cube"))
            CreateCube();
        if (GUI.Button(new Rect(400, 100, 300, 300), "创建Sphere"))
            CreateSphere();
    }

    public void CreateCube()
    {   //随机位置
        Vector3 pos1 = new Vector3(Random.Range(-20, 20), 0, Random.Range(-20, 20));
        //生成的游戏物体
        GameObject v = pool.CreateObject(keys[0], pre[0], pos1, Quaternion.identity);
        //两秒后开始回收
        StartCoroutine(recycling(v));
    }
    public void CreateSphere()
    {   //随机位置
        Vector3 pos1 = new Vector3(Random.Range(-20, 20), 0, Random.Range(-20, 20));
        //生成的游戏物体
        GameObject v = pool.CreateObject(keys[1], pre[1], pos1, Quaternion.identity);
        //两秒后开始回收
        StartCoroutine(recycling(v));
    }

    IEnumerator recycling(GameObject v)
    {   //两秒后调用回收方法
        yield return new WaitForSeconds(2.0f);
        pool.CollectObject(v);
    }
}

Unity 中的对象池是一种资源管理技术,用于在游戏运行过程中高效地创建、管理和回收对象。对象池的主要目的是减少频繁创建和销毁对象带来的性能开销,尤其是在有大量短期使用对象(如小敌人、项目等)的情况下。 下面是使用 Unity 对象池的基本步骤: 1. 创建对象池:首先,你需要创建一个包含所需对象类型的新对象池。这通常是一个静态类或专用脚本,负责管理对象的生命周期。 ```csharp public class ObjectPool<T> where T : Component { private List<T> poolObjects; private Stack<T> availableObjects; // 初始化方法 public ObjectPool(int initialSize) { poolObjects = new List<T>(); for (int i = 0; i < initialSize; i++) { T obj = Instantiate<T>(); obj.SetActive(false); // 设置对象为非活动状态,直到需要时才激活 poolObjects.Add(obj); } availableObjects = new Stack<T>(poolObjects); } // 获取对象 public T BorrowObject() { if (availableObjects.Count > 0) { T obj = availableObjects.Pop(); obj.SetActive(true); return obj; } else { T obj = Instantiate<T>(); return obj; } } // 归还对象 public void ReturnObject(T obj) { obj.SetActive(false); availableObjects.Push(obj); } } ``` 2. 使用对象池:当你需要一个新对象时,从池中借用一个,用完后记得归还。这样,当对象不再被使用时,它会被放回池而不是直接销毁,以便后续其他地方可能需要它。 ```csharp private ObjectPool<MyObject> objectPool; void Start() { objectPool = new ObjectPool<MyObject>(10); } void Update() { MyObject newObj = objectPool.BorrowObject(); // 使用 newObj ... newObj.gameObject.SetActive(false); // 当对象不再需要时,归还给池子 // 如果对象池已满,考虑创建更多对象 if (objectPool.availableObjects.Count == 0 && poolSize < MaxPoolSize) { // 添加新对象到池中 objectPool.poolObjects.Add(Instantiate<MyObject>()); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值