Unity对象池和自写对象池

这篇具有很好参考价值的文章主要介绍了Unity对象池和自写对象池。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一. 什么是对象池

二、创建对象池

1、Stack

①Stack类

<1>构造函数

<2>属性

<3>方法

②Stack对象池

2、Queue

①Queue类

<1>构造函数

<2>属性

<3>方法

②Queue对象池

3.Unity官方对象池

①Object Pool类

<1>构造函数

<2>属性

<3>方法

②Object Pool对象池


一. 什么是对象池

顾名思义就是一定数量的已经创建好的对象(Object)的集合。当需要创建对象时,先在池子中获取,如果池子中没有符合条件的对象,再进行创建新对象,同样,当对象需要销毁时,不做真正的销毁,而是将其setActive(false),并存入池子中,这样就避免了大量对象的创建。

好处:降低性能,减少反复生成和摧毁产生的大量GC。

坏处:

①回收过程复杂度增加,在下次使用的同时,需要清空回收前的数据。

②生命周期比其他的对象较长。

二、创建对象池

下面提供三种方法,一种是Stack栈,一种是Queue队列以及Unity官方封装的对象池。

1、Stack

在开始之前我们需要了解Stack是什么,可以将他看成一个可以什么都装的容器,特点是后进先出,什么意思呢,就像我们上下楼一样,当我们从1楼走上5楼的时候,我们是从5楼走下来,而不是从1楼走下来。举个“Hello World  ! ”的例子:

进栈:

Unity对象池和自写对象池,Unity,c#,unity,游戏引擎     Unity对象池和自写对象池,Unity,c#,unity,游戏引擎       Unity对象池和自写对象池,Unity,c#,unity,游戏引擎            Unity对象池和自写对象池,Unity,c#,unity,游戏引擎

出栈:

Unity对象池和自写对象池,Unity,c#,unity,游戏引擎Unity对象池和自写对象池,Unity,c#,unity,游戏引擎Unity对象池和自写对象池,Unity,c#,unity,游戏引擎

可以看见是后进先出的。

①Stack类

<1>构造函数

Stack():初始化Stack类的新实例,该实例为空并且具有默认初始容量。

Stack(ICollection):初始化Stack类的新实例,该实例包含从指定集合复制的元素并且具有与所复制的元素数相同的初始容量。

Stack(Int32):初始化Stack类的新实例,该实例为空并且具有指定的初始容量或默认初始容量(这两个容量中的较大者)。

<2>属性

Count:获取 Stack 中包含的元素数。

IsSynchronized:获取一个值,该值指示是否同步对 Stack 的访问(线程安全)

SyncRoot:获取可用于同步对 Stack 的访问的对象。

<3>方法

红色为常用方法:

Clear():从 Stack 中移除所有对象。

Clone():创建 Stack 的浅表副本。

Contains(Object):确定某元素是否在 Stack 中。

CopyTo(Array, Int32):从指定的数组索引处开始,将 Stack 复制到现有的一维 Array中。

Equals(Object):确定指定对象是否等于当前对象。(继承自 Object)

GetEnumerator():返回IEnumerator 的 Stack。

GetHashCode():作为默认哈希函数。(继承自 Object)

GetType():获取当前实例的 Type。(继承自 Object)

MemberwiseClone():创建当前 Object 的浅表副本。(继承自 Object)

Peek():返回位于 Stack 顶部的对象但不将其移除。

Pop():删除并返回 Stack 顶部的对象。

Push(Object):在Stack的顶部插入一个对象。

Synchronized(Stack):返回Stack的同步(线程安全)包装。

ToArray():将 Stack 复制到新数组中。

ToString():返回表示当前对象的字符串。(继承自 Object)

②Stack对象池

首先写一个对象池接口,毕竟可能我们有着不同的对象池,直接写泛型的对象池,写个委托,可以我们在回收以及获取的时候,还需要处理其他的逻辑。

public interface IPool<T>
{
    public delegate void CallBack();
    void Get(CallBack callBack = null);
    void Release(T gameobject, CallBack callBack = null);
    void Create();
    void Destroy(T gameobject);
}

然后我们写一个BasePool来实现IPool接口,其实看起来也不是很难,就是对Stack的进栈以及出栈做调整。

using System.Collections.Generic;
using UnityEngine;

public class BasePool : IPool<GameObject>
{
    protected GameObject insGameObject;
    public Stack<GameObject> pool;
    //创建一个带参数的构造函数是因为我的项目里面有需求,可以根据直接的需求改或者不要
    public BasePool(GameObject gameObject)
    {
        this.insGameObject = gameObject;
        pool = new Stack<GameObject>();
    }

    public virtual void Create()
    {
        GameObject go = GameObject.Instantiate(insGameObject);
        /*
         * 添加对应的组件....
         */
        pool.Push(go);
        pool.Pop();
    }
    public virtual void Destroy(GameObject gameobject)
    {
    }

    public virtual void Get(IPool<GameObject>.CallBack callBack = null)
    {
        if (pool.Count == 0)
        {
            //当pool没有东西的时候就直接创建一个
            Create();
        }
        else
        {
            //将物体重新拿出来
            GameObject go = pool.Pop();
          /*
           * 添加对应的组件....
           */
            go.SetActive(true);
        }
        //处理逻辑
        if (callBack != null)
        {
            callBack();
        }
    }
    public virtual void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
    {
        //回收的时候需要做什么
        if (callBack != null)
        {
            callBack();
        }
        gameobject.SetActive(false);
        pool.Push(gameobject);
    }
}

 其实对于上面来说已经是简单的弄好了,下面的是怎么使用,创建一个TestPool继承BasePool,

using UnityEngine;

public class TestPool : BasePool
{
    public TestPool(GameObject gameObject) : base(gameObject)
    {
        
    }
    public override void Get(IPool<GameObject>.CallBack callBack = null)
    {
        base.Get(callBack);
    }

    public override void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
    {
        base.Release(gameobject, callBack);
    }

    public override void Destroy(GameObject gameobject)
    {
        base.Destroy(gameobject);
    }
    public override void Create()
    {
        base.Create();
    }
}

 在你需要使用到的地方,按照下方的样子就可以运作起来了,具体的业务要求还是得你自己具体的实现。

 public void PoolTest()
 {
     //实例化一个对象池
     TestPool testPool = new TestPool(/*传入需要生成的GameObject*/);
     testPool.Get();
     /*传入需要生成的GameObject,也可以选着是否重置Game Object上的组件以及重置数据*/
     testPool.Release(gameObject,test);
 }
 private void test()
 {
     /*
      处理逻辑
      */
 }

2、Queue

和Stack不同的是,Queue特点是先进先出,什么意思呢,我们排队买早餐,先排队的人可以先买到早餐然后先离开,举个“Hello World  ! ”的例子:

进列:

 Unity对象池和自写对象池,Unity,c#,unity,游戏引擎     Unity对象池和自写对象池,Unity,c#,unity,游戏引擎       Unity对象池和自写对象池,Unity,c#,unity,游戏引擎            Unity对象池和自写对象池,Unity,c#,unity,游戏引擎

出列:

Unity对象池和自写对象池,Unity,c#,unity,游戏引擎Unity对象池和自写对象池,Unity,c#,unity,游戏引擎Unity对象池和自写对象池,Unity,c#,unity,游戏引擎

①Queue类

<1>构造函数

Queue():初始化Queue类的新实例,该实例为空,具有默认初始容量并使用默认增长因子。

Queue(ICollection):初始化 Queue 类的新实例,该实例包含从指定集合复制的元素,具有与所复制的元素数相同的初始容量并使用默认增长因子。

Queue(Int32):初始化 Queue 类的新实例,该实例为空,具有指定的初始容量并使用默认增长因子。

Queue(Int32,Single):初始化Queue类的新实例,该实例为空,具有指定的初始容量并使用指定的增长因子。

<2>属性

Count:获取Queue中包含的元素数。

IsSynchronized:获取一个值,该值指示是否同步对Queue的访问(线程安全)

SyncRoot:获取可用于同步对Queue的访问的对象。

<3>方法

红色为常用方法:

Clear():从Queue中移除所有对象。

Clone():创建 Queue 的浅表副本。

Contains(Object)确定某元素是否在Queue中。

CopyTo(Array, Int32):从指定数组索引开始将 Queue 元素复制到现有一维 Array 中。

Dequeue()移除并返回位于Queue开始处的对象。

Enqueue(Object)将对象添加到Queue的结尾处。

Equals(Object)确定指定对象是否等于当前对象。(继承自 Object)

GetEnumerator():返回循环访问 Queue 的枚举数。GetHashCode)作为默认哈希函数。(继承自 Object)

GetType():获取当前实例的 Type。(继承自Object)

MemberwiseClone():创建当前 Object 的浅表副本。(继承自 Object)

Peek():返回位于 Queue 开始处的对象但不将其移除。

Synchronized(Queue):返回将包装原始队列并且是线程安全的新的 Queue。

ToArray():将 Queue 元素复制到新数组。

ToString():返回表示当前对象的字符串。(继承自 Object)

TrimToSize():将容量设置为 Queue 中元素的实际数目。

②Queue对象池

其实关于Queue写的对象池和Stack写的对象池没什么区别只不过是使用的类不一样。创建一个BaseQueuePool的Queue类的对象池。

using System.Collections.Generic;
using UnityEngine;

public class BaseQueuePool : IPool<GameObject>
{
    protected GameObject insGameObject;

    public Queue<GameObject> pool;
    public void Create()
    {
        GameObject go = GameObject.Instantiate(insGameObject);
        go.SetActive(true);
        pool.Enqueue(go);
        pool.Dequeue();
    }

    public void Destroy(GameObject gameobject)
    {
    }

    public void Get(IPool<GameObject>.CallBack callBack = null)
    {
        if (pool.Count == 0)
        {
            //当pool没有东西的时候就直接创建一个
            Create();
        }
        else
        {
            //将物体重新拿出来
            GameObject go = pool.Dequeue();
            go.SetActive(true);
        }
        if (callBack != null)
        {
            callBack();
        }
    }

    public void Release(GameObject gameobject, IPool<GameObject>.CallBack callBack = null)
    {
        //回收的时候需要做什么
        if (callBack != null)
        {
            callBack();
        }
        gameobject.SetActive(false);
        pool.Enqueue(gameobject);
    }
}

然后使用方法是和上面用Stack类写的用法一样。

3.Unity官方对象池

当然,不想自己写对象池也是可以的,Unity为我们封装好对象池。

①Object Pool类

<1>构造函数

public ObjectPool<T0>(Func<T> createFunc, Action<T> actionOnGet, Action<T> actionOnRelease, Action<T> actionOnDestroy, bool collectionCheck, int defaultCapacity, int maxSize);

构造函数需要传入7个参数,它们按顺序分别是:

createFunc:用于在池为空时创建新实例。在大多数情况下,这只是()=> new T()。

actionOnGet:从池中获取实例时调用。

actionOnRelease:当实例返回到池时调用。这可用于清理或禁用实例。

actionOnDestroy:当由于池达到最大大小而无法将元素返回到池时调用。

collectionCheck:将实例返回到池时执行集合检查。如果实例已经在池中,则会抛出异常。集合检查只在编辑器。

defaultCapacity:创建堆栈时使用的默认容量。

maxSize:池的最大大小。当池达到最大大小时,返回到池中的任何其他实例都将被忽略,并可以被垃圾收集。这可以用来防止池增长到非常大的规模

<2>属性

CountActive:池已创建但当前正在使用且尚未返回的对象数。

CountAll:活动和非活动对象的总数。

CountInactive:池中当前可用的对象数。

<3>方法

Clear:删除所有池项。如果池包含destroy回调函数,那么它将被池中的每个项目调用。

Dispose:删除所有池项。如果池包含destroy回调函数,那么它将被池中的每个项目调用。

Get:从池中获取实例。如果池为空,则将创建一个新实例。

Release:将实例返回到池中。

②Object Pool对象池

using UnityEngine;
using UnityEngine.Pool;

public class UnityPool : MonoBehaviour
{
    private ObjectPool<GameObject> pool;
    //池子初始化大小
    int poolSize = 20;
    //池子最大数量
    int poolMaxSize = 100;

    private void Start()
    {
        pool = new ObjectPool<GameObject>(OnCreate, OnGet, OnRelease, OnDestroy, true, poolSize, poolMaxSize);

    }
    /// <summary>
    /// 实例化对象
    /// </summary>
    /// <returns></returns>
    private GameObject OnCreate()
    {
        /*实例化需要使用对象池的物体*/
        GameObject go = Instantiate();
        /*
         添加需要的组件
        或者其他逻辑
         */
        return go;
    }
    /// <summary>
    /// 获取对象池内的实例
    /// </summary>
    /// <param name="object"></param>
    private void OnGet(GameObject obj)
    {
        obj.SetActive(true);
    }
    /// <summary>
    /// 回收实例到对象池
    /// </summary>
    /// <param name="obj"></param>
    private void OnRelease(GameObject obj)
    {
        /*
         * 回收前需要的逻辑
         */
        obj.SetActive(false);
    }
    /// <summary>
    /// 销毁实例
    /// </summary>
    /// <param name="obj"></param>
    private void OnDestroy(GameObject obj)
    {
        Destroy(obj);
    }
}

 使用方法也是和上方Stack写的对象池一样。文章来源地址https://www.toymoban.com/news/detail-811200.html

到了这里,关于Unity对象池和自写对象池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity--随机生成游戏对象

    在脚本中声明数组 RandomObjects 用于保存生成对象的类型,在project文件中拖入对象。 先将脚本拖到一个对象上,然后点击检查器-覆盖-应用到全部,这样将使所有预制件都拥有该属性。

    2024年02月15日
    浏览(40)
  • Unity vs Godot :哪个游戏引擎更适合你?

    游戏引擎的选择对开发过程和最终产品质量有着重大影响。近年来,Godot和Unity这两款引擎受到广泛关注。本文将从多个维度对两者进行比较,以期为开发者提供正确的选择建议。 Godot和Unity都有各自的优势,没有绝对的好坏之分。Godot开源免费,上手简单,更适合2D和小型游戏

    2024年01月23日
    浏览(94)
  • 30分钟了解所有引擎组件,132个Unity 游戏引擎组件速通!【收藏 == 学会】

    🎬 博客主页:https://xiaoy.blog.csdn.net 🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN 🙉 🎄 学习专栏推荐:Unity系统学习专栏 🌲 游戏制作专栏推荐:游戏制作 🌲Unity实战100例专栏推荐:Unity 实战100例 教程 🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! 📆 未来很长

    2024年02月11日
    浏览(69)
  • Unity Physics2D 2d物理引擎游戏 笔记

    2d 材质 里面可以设置 摩擦力 和 弹力 Simulated:是否在当前的物理环境中模拟,取消勾选该框类似于Disable Rigidbody,但使用这个参数更加高效,因为Disable会销毁内部产生的GameObject,而取消勾选Simulated只是禁用。 Kinematic 动力学刚体 动力学刚体不受重力和力的影响,而受用户的

    2023年04月24日
    浏览(121)
  • Unity 3D:获取未激活游戏对象的方法

    一、获取已激活游戏对象 Gameobject.Find(\\\"游戏对象名\\\") //根据对象名直接获取游戏对象 这个方法可以找到指定的对象,但是一些缺陷。 1、如果场景中有重名,此方法找到的是Hierarchy从上至下第一次出现此对象名的对象。 2、如果对象的activeSelf为false,那么这个方法永远无法找到

    2023年04月08日
    浏览(44)
  • Unity和UE4两大游戏引擎,你该如何选择?

    目录 游戏引擎 2 —— 难易区别 编程语言 3 —— 游戏产品 UE4制作的游戏产品  Unity制作的游戏产品  产品类型 5 —— 资源商店 6 —— 人才需求 平均薪资 总结      Unity和UE4都是游戏引擎,所谓游戏引擎就是集成了复杂功能的游戏开发软件,他们帮我们实现了复杂的底层逻

    2023年04月08日
    浏览(69)
  • GODOT游戏引擎简介,包含与unity性能对比测试,以及选型建议

    GODOT,是一个免费开源的3D引擎。本文以unity作对比,简述两者区别和选型建议。由于是很久以前写的ppt,技术原因视频和部分章节丢失了。建议当做业务参考。 GODOT目前为止遇到3个比较重大的机遇,第一个是oprea的合作奖,第二个是用支持c#换来的微软的投资,第三个是虚幻

    2024年02月14日
    浏览(81)
  • Unity中获取游戏对象的几种方式

    在学习如何获取物体和组件时先明白说明什么是物体,组件和对象。 物体:unity中在层级显示的东西都可以叫做物体 组件:unity中提供了大量已经写好的组件,比如刚体,碰撞体等,自己 编写的脚本也是一种组件类 对象:挂载到物体上的脚本是一个实例化的组件,也就是一

    2024年01月17日
    浏览(37)
  • unity 之 GetComponent 获取游戏对象上组件实例方法

    GetComponent 是Unity引擎中用于获取游戏对象上组件实例的方法。它允许您从游戏对象中获取特定类型的组件,以便在脚本中进行操作和交互。 GetComponent ComponentType (): 这是一个泛型方法,用于从当前游戏对象上获取指定类型的组件。在 ComponentType 部分,您应该提供您想要获取的

    2024年02月02日
    浏览(46)
  • Java基础-多线程&JUC-线程池和自定义线程池

    主要核心原理 不推荐Executors创建没有上线的线程池,建议使用自定义的线程池; Java工具类创建线程池; 当只有3个任务时,直接上处理机运行; 当有6个任务时,任务1-3上处理机运行,任务4-6进入阻塞队列等待; 当有9个任务时,任务1-3上处理机运行,任务4-6进入阻塞队列等

    2024年02月12日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包