Unity优化篇:对象池的创建与使用。(简单且实用)

1.对象池是什么?

对象池是一种Unity经常用到的内存管理服务,它的作用在于可以减少创建每个对象的系统开销。

2.为什么要使用对象池?

在Unity游戏开发的过程中经常会创建一些新的对象,如果数量较少还可以接受,如果创建的新对象数量庞大,那么对内存而言是一个极大的隐患。例如射击游戏当中,每发射一颗子弹,都要创建一个新的子弹对象,那么子弹是数量庞大,可想而知一场游戏当中会创建多少这样的新对象,那么如果这些子弹创建之后都对游戏起着关键且持续性的作用也无可厚非,问题是子弹发射完成之后,几秒之后就不再拥有任何的意义,一般会将它自动的隐藏,也就是我们所说的SetActive(false),因此大量的非活跃对象出现在游戏场景当中。

3.怎么创建并使用对象池?

对象池背后的理念其实是非常简单的。我们将对象存储在一个池子中,当需要时在再次使用,而不是每次都实例化一个新的对象。池的最重要的特性,也就是对象池设计模式的本质是允许我们获取一个“新的”对象而不管它真的是一个新的对象还是循环使用的对象。

我们需要两个字典,一个动态存储和去除当前所需要的游戏物体,另一个当记事本,记录那些游戏物体被记录过,那些没有,并且据此来判定是否需要创建新的对象池。

下面是对象池的代码,(参考https://www.cnblogs.com/yugejuhao/p/7677497.html

创建对象池:

   我修改了一下GetObj函数,让它能在指定位置生成游戏物体。

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

public class ObjectPool
{
    public const string stoneExplosion = "done_explosion_asteroid";
    public const string enemyExplosion = "done_explosion_enemy";
    public const string playerExplosion= "done_explosion_player";
    public const string redStone = "Asteroid_Lrg_B_01";
    public const string boss1 = "Boss1";
    public const string shuijing = "Crystal_Lrg_A_01";
    public const string blackStone = "Done_Asteroid 02";
    public const string playerAttack = "Done_Bolt";
    public const string enemyAttack = "Done_Bolt-Enemy";
    public const string player = "Done_Player";
    public const string purpleEnemy = "Done_PurpleEnemy";
    public const string redEnemy = "Done_RedEnemy";

    /// <summary>
    /// 对象池
    /// </summary>
    private Dictionary<string, List<GameObject>> pool;

    /// <summary>
    /// 预设体
    /// </summary>
    private Dictionary<string, GameObject> prefabs;
    #region 单例
    private static ObjectPool instance;
    private ObjectPool()
    {
        pool = new Dictionary<string, List<GameObject>>();
        prefabs = new Dictionary<string, GameObject>();
    }
    public static ObjectPool GetInstance()
    {
        if (instance == null)
        {
            instance = new ObjectPool();
        }
        return instance;
    }
    #endregion


    /// <summary>
    /// 从对象池中获取对象
    /// </summary>
    /// <param name="objName"></param>
    /// <returns></returns>
    public GameObject GetObj(string objName,Vector3 position,Quaternion quaternion)
    {
        //结果对象
        GameObject result = null;
        //判断是否有该名字的对象池
        if (pool.ContainsKey(objName))
        {
            //对象池里有对象
            if (pool[objName].Count > 0)
            {
                //获取结果
                result = pool[objName][0];
                //激活对象
                result.transform.position = position;
                result.transform.rotation = quaternion;
                result.SetActive(true);
                //从池中移除该对象
                pool[objName].Remove(result);
                //返回结果
                return result;
            }
        }
        //如果没有该名字的对象池或者该名字对象池没有对象

        GameObject prefab = null;
        //如果已经加载过该预设体
        if (prefabs.ContainsKey(objName))
        {
            prefab = prefabs[objName];
        }
        else     //如果没有加载过该预设体
        {
            //加载预设体
            prefab = Resources.Load<GameObject>("Prefabs/" + objName);
            //更新字典
            prefabs.Add(objName, prefab);
        }

        //生成
        result = Object.Instantiate(prefab);
        result.transform.position = position;
        result.transform.rotation = quaternion;
        //改名(去除 Clone)
        result.name = objName;
        //返回
        return result;
    }

    /// <summary>
    /// 回收对象到对象池
    /// </summary>
    /// <param name="objName"></param>
    public void RecycleObj(GameObject obj)
    {
        //设置为非激活
        obj.SetActive(false);
        //判断是否有该对象的对象池
        if (pool.ContainsKey(obj.name))
        {
            //放置到该对象池
            pool[obj.name].Add(obj);
        }
        else
        {
            //创建该类型的池子,并将对象放入
            pool.Add(obj.name, new List<GameObject>() { obj });
        }

    }

}



 

使用对象池:

           把用到Instantiate的地方替换为GetObj,

           把用到Destroy的地方替换为RecycleObj,

注意点:

1.由于对象池是采用将游戏物体的状态设置为true和false来实现目的,所以有些游戏物体挂载的脚本的Start()函数和Awake()函数需要根据情况来更改一下。(可以考虑一下OnEnable,OnDisable

2.正如这位大神所说https://www.cnblogs.com/mezero/p/3955130.html

  • 很多类型的对象被重新使用前,在某些情况下,需要被reset。至少,所有的成员变量都要设置成初始值。这可以在池中实现而不需要用户处理。何时和如何重置需要考虑以下两个方面:
    • 重置是立即的(例如,在存储对象时即重置)还是延迟的(例如,在对象被重新使用后重置)。
    • 重置是被池管理(例如,对于被放入池中的对象来说是透明的)还是声明池对象的类。
  • 创建管理所有类型池的ObjectPool。
  • 某些类型的资源是很珍贵的(如数据库连接),池需要显示上限并提供一个针对分配对象失败的安全措施;
  • 当池中对象很多却很少使用时,或许需要收缩的功能(不管是自动的还是强制的)。
  • 最后,池可以被多个线程共享,因此需要实现为线程安全的。
  • 那么其中那些是必需的呢?你的答案或许和我的不一样,但请允许我阐述我的观点:

  • 重置是必需的。但是正如你将在下面看的那样,我并没有强制到底是在池中还是被管理类中处理重置逻辑。你可能两种都需要,之后的代码中我将向你展示各自两个版本。
  • Unity强制限制多线程。你可以在主线程中定义工作者线程,但只有主线程可以调用Unity API。以我的经验看来,我们并不需要将池实现为支持多线程。
  • 仅个人而言,我并不介意每次为一个类型申明一个新的池。可选的方案是采用单例模式:创建一个新的对象池并放置于存储池的字典中,该字典放置在一个静态变量中。为了安全使用,你需要将将你的对象池实现为支持多线程。但就我看到的对象池而言没有一个是100%安全的。
  • 在本篇文章中我重点处理内存。其它类型资源池也是很重要的,但超出本篇文章的范围。这很大程度上减少了以下的需求:
    • 不需要一个作限制用的最大值。如果你的游戏使用太多的资源,你已经陷入麻烦了,对象池也救不了你。
    •  我们也可以假设没有其它进程等待你尽快释放内存。这就意味着重置可以是延迟的,也不需要提供收缩功能。

总结:本篇所说的对象池是非常简单且基础的。适用于游戏物体频繁生成与销毁项目。如果有复杂的需求,这个方法肯定不适用。仅供参考。

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Unity WebRTC是一个用于在Unity游戏引擎中实现实时通信的开源库。这个库使用WebRTC标准,可以在Unity项目中创建点对点的音视频通信。 Unity WebRTC库的主要部分是一个C#的API,它提供了一个简单易用的接口,可以让开发人员在游戏中的对象之间进行实时通信。开发人员可以通过该API创建音频通话、视频通话甚至数据通信。 Unity WebRTC库提供了一整套功能,包括加载媒体设备、采集音视频数据流、编码解码、传输以及呈现。开发人员可以通过调用适当的API函数,实现对各种通信操作的控制。 在Unity WebRTC文档中,开发人员可以找到关于如何在项目中集成和使用Unity WebRTC库的详细说明。文档内容涵盖了库的安装、配置、API的使用方法以及常见问题解答。 文档的第一部分介绍了Unity WebRTC库的概述和基本概念。开发人员可以了解到WebRTC在实时通信中的作用、库的基本结构以及支持的平台和设备。 接下来的一部分是有关安装和配置Unity WebRTC库的指南。在这里,开发人员可以找到关于如何下载和导入库的说明,以及如何在项目中配置WebRTC相关的设置。 文档的重点是介绍Unity WebRTC库的API和用法。开发人员可以了解到如何创建本地和远程对象、如何建立连接、如何进行音视频传输,以及如何处理通信错误和异常。 最后,文档中还包含了一些示例代码和教程,以帮助开发人员更好地理解和使用Unity WebRTC库。这些示例可以帮助开发人员快速上手使用库的各种功能,并加速实现实时通信的过程。 总结来说,Unity WebRTC文档提供了详尽的关于Unity WebRTC库的使用和集成的指南。通过这些文档,开发人员可以迅速了解和掌握Unity WebRTC库,并在自己的项目中实现实时音视频通信功能。 ### 回答2: Unity WebRTC 是一种用于实时通信的技术,让开发者可以在 Unity 游戏或应用中实现音频和视频通话功能。Unity WebRTC 提供了一套完整的开发文档,以帮助开发者了解和使用这个技术。 Unity WebRTC 文档包含了详细的介绍、教程和示例代码,帮助开发者快速掌握基本概念和使用方法。开发者可以从文档中了解到如何创建音视频通话的场景,如何处理用户输入和控制呼叫连接过程。 文档中还提供了丰富的 API 文档和参考资料,包括各种方法、属性和事件的详细说明,帮助开发者更好地理解和使用 Unity WebRTC 的功能。开发者可以根据需求和情况,选择合适的 API 进行调用和操作。 此外,Unity WebRTC 文档还包含了一些常见问题和解决方案,帮助开发者解决在使用过程中可能遇到的一些问题和困惑。这些问题涵盖了网络连接、音视频处理、安全性等方面,可以帮助开发者更好地优化和调试自己的应用。 总之,Unity WebRTC 文档提供了全面而详尽的开发指南,帮助开发者迅速上手和应用这项技术。凭借文档中的介绍和示例代码,开发者可以轻松实现音视频通话功能,并根据自己的需求进行扩展和优化。无论是初学者还是有经验的开发者,都可以通过这份文档,快速掌握 Unity WebRTC 的使用方法,为自己的项目添加实时通信能力。 ### 回答3: Unity WebRTC是基于WebRTC技术的Unity插件,用于在Unity项目中实现实时音视频通信功能。WebRTC(Web Real-Time Communication)是一种支持浏览器之间进行实时通信的开放标准,能够实现高质量的音视频传输和实时数据传递。 Unity WebRTC文档提供了详细的使用指南和API参考,帮助开发者快速上手并实现各种功能。文档中包含了Unity WebRTC的安装和配置说明,以及示例代码和实用工具,方便开发者进行开发和调试。 文档首先介绍了Unity WebRTC的基本概念和工作原理,包括信令服务器、ICE候选者、数据通道等。然后详细介绍了如何在Unity项目中使用Unity WebRTC插件,包括创建音视频流、建立连接、发送和接收数据等。 文档还提供了一些常见的应用场景和示例代码,比如实时音视频通话、屏幕共享、多人游戏等。开发者可以借助这些示例代码和场景,快速实现自己的应用功能。 此外,文档还介绍了一些高级功能和技巧,如媒体轨道控制、音频处理和编解码等。开发者可以根据自身需求,深入学习和使用这些高级功能,提升应用的质量和用户体验。 总的来说,Unity WebRTC文档详细全面,对于开发者来说是一个重要的参考资料。通过学习和使用文档中的内容,开发者可以轻松实现实时音视频通信功能,并快速构建高质量的WebRTC应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值