游戏引擎:Unity
版本:2019.4.6f1 【2017版本以上均可】
编译平台:Visual Studio 2019

前要

  在开发过程中,很多时候会出现针对某一GameObject的频繁创建与销毁这类问题,从性能上认为这种行为是极度损耗的,为避免对性能的不必要损耗,出现 游戏对象池 的优化解决方案。

原理

  Unity中 GameObject 的创建与销毁,分别依赖于 CPU内存,对于频繁创建和销毁 GameObject 的行为是十分消耗 CPU 的性能。为避免 CPU 不必要的性能开支(负荷),出现以内存为主要对象,预先准备相当的GameObject数量存储于内存中,仅通过CPU激活/禁用这类 GameObject 对象来减轻 CPU 的工作负荷。

  简言:放弃单独的分配和释放对象,从固定的池中重用对象,以实现节约内存使用率和提供性能。

代码块

  对象池适用的对象为频繁创建的游戏对象,对象池需要经过[创建-回收]过程。

一、完整代码展示

  注:文本中GetInstance为单例,详见快捷链接。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;namespace Tool
{/// <summary>/// 对象池/// </summary>public class ObjectPool : GetInstance<ObjectPool>{public interface IResetable {void OnReset(); }//1.池private Dictionary<string, List<GameObject>> cache;protected override void Init(){base.Init();cache = new Dictionary<string, List<GameObject>>();}//2.创建public GameObject CreateObject(string type, GameObject prefab, Vector3 position, Quaternion rotation){//(1)查找可使用的游戏对象GameObject targetObject = null;//     检查是否包含对象if (cache.ContainsKey(type)){targetObject = cache[type].Find(e => !e.activeInHierarchy);}else{cache.Add(type, new List<GameObject>());}//(2)如果没有则创建并加入到对象池中if (targetObject == null){targetObject = Object.Instantiate(prefab);cache[type].Add(targetObject);}//(3)设置位置,使用对象targetObject.transform.position = position;targetObject.transform.rotation = rotation;targetObject.SetActive(true);//targetObject.GetComponent<IResetable>().OnReset();//foreach (var item in targetObject.GetComponents<IResetable>()){item.OnReset();}return targetObject;}//3.回收private void CollectObject(GameObject targetObject){targetObject.SetActive(false);}private IEnumerator DelayCollectObject(GameObject targetObject, float delayTime){yield return new WaitForSeconds(delayTime);CollectObject(targetObject);}/// <summary>/// 回收[封装]/// </summary>/// <param name="targetObject">游戏对象</param>/// <param name="delayTime">延迟时间</param>public void CollectObject(GameObject targetObject, float delayTime = 0f){if (delayTime == 0){CollectObject(targetObject);}else{StartCoroutine(DelayCollectObject(targetObject, delayTime));}}}
}

二、代码内容详解

2.1 创建对象池

  对象池是存储Prefab[预制件],创建物体对象,需要获取[对象名称]、[对象预制件]、[对象坐标]、[对象自身角度]信息。创建对象的过程中需要检查场景中是否存在这个对象,有则使用,无则创建新的使用。

/// <summary>
/// 创建
/// <summary>
/// type:物品类型 prefab:物体预制件 position:物体出现位置 rotation:物体出现方向
public GameObject CreateObject(string type, GameObject prefab, Vector3 position, Quaternion rotation)
{public interface IResetable {void OnReset(); }//(1)查找可使用的游戏对象GameObject targetObject = null;   //     检查是否包含对象if (cache.ContainsKey(type))targetObject = cache[type].Find(e => !e.activeInHierarchy);elsecache.Add(type, new List<GameObject>());  //(2)如果没有则创建并加入到对象池中if (targetObject == null){targetObject = Object.Instantiate(prefab);cache[type].Add(targetObject);}//(3)设置位置,使用对象targetObject.transform.position = position;targetObject.transform.rotation = rotation;targetObject.SetActive(true);//targetObject.GetComponent<IResetable>().OnReset();//foreach (var item in targetObject.GetComponents<IResetable>()){item.OnReset();}return targetObject;
}

2.2 回收对象

2.2.1 回收方法

  回收方式采用的是禁用物体,而非销毁物体,让物体持续存在于内存当中。Unity本身提供了禁用方法,即[SetActive(bool isActive)]。如下所示,填入[false]表示这个GameObject对象被禁用,而非销毁。

//3.回收
private void CollectObject(GameObject targetObject)
{targetObject.SetActive(false);
}
2.2.2 回收需求拓展:延时回收

  随着需求的变更,我们不仅仅是希望立刻禁用,也出现延时禁用的实际需求,在Unity中的 命名空间[UnityEngine] 为我们提供了 协程[IEnumerator] 这一便捷的帮助,如图所示:

private IEnumerator DelayCollectObject(GameObject targetObject, float delayTime)
{yield return new WaitForSeconds(delayTime);CollectObject(targetObject);
}
2.2.3 回收需求的封装【支持立即回收与延时回收】

  随着需求的增多,回收的方法种类也随之增多,在使用这些回收方法的过程中,因为过多的命名或调用方法而迷糊不清各回收方法的差异点。所以我们封装回收的方法,仅通过一个调用方法,多层重载来简明调用,而不是同类型的方法群中一个个查找调用。

/// <summary>
/// 回收[封装]
/// </summary>
/// <param name="targetObject">游戏对象</param>
/// <param name="delayTime">延迟时间</param>
public void CollectObject(GameObject targetObject, float delayTime = 0f)
{if (delayTime == 0){CollectObject(targetObject);}else{StartCoroutine(DelayCollectObject(targetObject, delayTime));}
}

更多说明

  如有文章错误,请留言指明,笔者将在第一时间内修正错误。

【Unity】游戏对象池ObjectPool相关推荐

  1. [Unity] unity中对象池的使用

    在现代游戏引擎设计中中,使用的大多都是托管内存,基于此我们不必手动管理内存,造成内存泄露等问题.对于unity中的游戏对象,每隔一段时间,Mono的垃圾回收机制将会检测内存,将没有再被引用的内存释放回 ...

  2. Unity中对象池的使用

    unity中用到大量重复的物体,例如发射的子弹,可以引入对象池来管理,优化内存. 对象池使用的基本思路是: 将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用.恰当地使用对象池,可以在 ...

  3. Unity 简易对象池

    "每隔x秒随机产生10-20个物体(cube或者sphere),要求显示在屏幕上,并在x秒的显示后将其回收".看似简单的题目小菜也楞是在紧张中满头大汗的调试了两个小时左右才得以完成 ...

  4. Unity游戏对象与图形基础

    游戏对象与图形基础 3D游戏设计第四次作业 前言 基本操作演练[建议做] 编程实践 动作分离设计思路 动作管理器的设计图 相对于上一版的更新 代码分析 核心代码(老师提供) 动作基类--SSActio ...

  5. Unity程序框架总结归置系列(2)——对象池

    上一篇--Unity程序框架总结归置系列(1)--单例基类 该说的,上一篇也说了.话不多说,直接开肝. unity对象池模块 先直接上源码: using System.Collections.Gene ...

  6. C#开发Unity游戏教程之游戏对象的行为逻辑方法

    C#开发Unity游戏教程之游戏对象的行为逻辑方法 游戏对象的行为逻辑--方法 方法(method),读者在第1章新建脚本时就见过了,而且在第2章对脚本做整体上的介绍时也介绍过,那么上一章呢,尽管主要 ...

  7. Unity的对象复用

    2019独角兽企业重金招聘Python工程师标准>>> 对象复用是 用空间换时间的一种典型的做法,对于Unity来说虽然引擎内部有GameObject的对象池,但是 这只是Nativ ...

  8. java对象工厂池_[转载]Java对象池技术的原理及其实现

    作者:汪永好 出处:计算机与信息技术 责任编辑: 方舟 [ 2006-11-25 07:00 ] 摘 要 :本文在分析对象池技术基本原理的基础上,给出了对象池技术的两种实现方式.还指出了使用对象池技术 ...

  9. java 对象池 博客_Java对象池技术的原理及其实现的小结

    一起学习 Java对象的生命周期大致包括三个阶段:对象的创建,对象的使用,对象的清除.因此,对象的生命周期长度可用如下的表达式表示:T = T1 T2 T3.其中T1表示对象的创建时间,T2表示对象的 ...

最新文章

  1. 软件中的易用性设计及测试(三)之实践
  2. 工作中常用到的sql命令!!!
  3. cmake的使用-为什么要使用CMake
  4. char * 转LPCTSTR若干方法
  5. 计算机安全事故由谁整改,信息安全检查整改方案 整改方案 .doc
  6. PC端中文机械设备企业网页模板
  7. drupal显示图片_Drupal在多样性和包容性方面显示领导力
  8. jetCache使用
  9. html2canvas 在qq保存失败_QQ的截图功能,没想到这么好用!
  10. 小知识--oppo R9sk手机刷机
  11. 计算机设置定时关机win10,Win10电脑如何设置定时关机?Win10电脑设置定时关机命令...
  12. 使用FlashBoot3.2c 将 U 盘制作成 DOS 启动盘
  13. 电脑编程和计算机编程有什么区别,机器人编程与电脑编程有何区别?官方专家为你详细解说!...
  14. 树莓派存储方案_如何在树莓派上搭建私有云存储
  15. switch判断语句用法
  16. python在线电影网站-四
  17. AE不能导入mov等格式文件
  18. 非root查看手机数据库和SharedPreferences的方法
  19. 实战--虚拟机用ffmpeg采集音频设备,并用rtmp推流
  20. 建模算法笔记 | 拟合算法

热门文章

  1. 前端网页配色网站推荐
  2. Mac min忘记登录密码
  3. com.netflix.hystrix.exception.HystrixRuntimeException short-circuited and no fallback available
  4. Cisco路由器的安全配置方案
  5. 微信公开课,视频号成主角,机会来了
  6. C语言魔王语言解释(没那么复杂)
  7. ECharts(3)
  8. 为什么java中的时间是从1970年1月1日开始的?
  9. OpenThreads库介绍——Block
  10. HTML5期末大作业:餐饮美食网站设计——上海美食介绍(6页) HTML+CSS+JavaScript HTML毕设网页设计 web学生网页设计作业源码