《Unity3D》通过对象池模式,管理场景中的元素
池管理类有啥用?
在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹、子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条、文字等等
这些元素共同的特性是:存在固定生命周期,使用比较频繁,场景中大量使用。
所以,我们就通过池管理思路,在游戏初始化的时候,生成一个初始的池,存放我们要复用的元素,
当要用到时,从池中取出;生命周期结束,放回到池中。
代码
这个池的参数有两个:1池中存放的元素 2 池的初始容量(如果池不够了,则会按照这个容量进行扩展)
代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine; /// <summary>
/// 通用的池管理类
/// </summary>
public class ObjectPoolManager : MonoBehaviour
{
#region 公共属性 /// <summary>
/// 池中所使用的元素Prefab
/// </summary>
public GameObject ObjPrefab; /// <summary>
/// 初始容量
/// </summary>
public int InitialCapacity; #endregion #region 私有属性 /// <summary>
/// 初始下标
/// </summary>
private int _startCapacityIndex; /// <summary>
/// 可用下标
/// </summary>
private List<int> _avaliableIndex; /// <summary>
/// 池中全部元素
/// </summary>
private Dictionary<int, GameObject> _totalObjList; #endregion #region 事件/重写方法 void Start()
{
_avaliableIndex = new List<int>(InitialCapacity);
_totalObjList = new Dictionary<int, GameObject>(InitialCapacity);
expandPool();
}
#endregion #region 公共方法 /// <summary>
/// 取得一个物体,返回值 1,obj代表,ID是1的物体被取到,ID可以用来归还物体的时候用到
/// </summary>
/// <returns></returns>
public KeyValuePair<int, GameObject> PickObj()
{ if (_avaliableIndex.Count == )
expandPool(); int id = _avaliableIndex[];
_avaliableIndex.Remove(id); _totalObjList[id].SetActive(true);
return new KeyValuePair<int, GameObject>(id, _totalObjList[id]);
} /// <summary>
/// 从池中取出元素,在制定时间后回收
/// </summary>
/// <param name="existSecond"></param>
/// <returns></returns>
public KeyValuePair<int, GameObject> PickObjWithDelayRecyle(float existSecond)
{
KeyValuePair<int, GameObject> obj = PickObj();
StartCoroutine(startRecycleExplosion(obj.Key, existSecond));
return obj;
} /// <summary>
/// 回收一个物体
/// </summary>
/// <param name="id"></param>
public void RecyleObj(int id)
{
_totalObjList[id].SetActive(false);
_totalObjList[id].transform.parent = transform;
_avaliableIndex.Add(id);
} #endregion #region 私有方法 IEnumerator startRecycleExplosion(int id, float waitTime)
{
yield return new WaitForSeconds(waitTime);
RecyleObj(id);
} /// <summary>
/// 扩展池
/// </summary>
private void expandPool()
{
int start = _startCapacityIndex;
int end = _startCapacityIndex + InitialCapacity; for (int i = start; i < end; i++)
{
//加入验证判断,避免在多个请求同时触发扩展池需求
if (_totalObjList.ContainsKey(i))
continue; GameObject newObj = Instantiate(ObjPrefab) as GameObject;
newObj.SetActive(false);
_avaliableIndex.Add(i);
_totalObjList.Add(i, newObj);
}
_startCapacityIndex = end;
}
#endregion
}
值得注意的是:放回池中的时候,我们把元素的父节点也设置为池元素,这样做是避免当元素挂载的对象在内存中被删除的时候,元素也被删除的问题。
调用
将本类挂载到场景中的某个GameObject上,在U3D编辑界面进行参数的赋值,就可以再游戏中访问了。
声明方式:
ObjectPoolManager _bulletPool = GameObject.Find("你挂载的物体名称").GetComponent<ObjectPoolManager>();
取出元素:
KeyValuePair<int, GameObject> bulletKV = _bulletPool.PickObj();
放回:
_bulletPool.RecyleObj(bulletID);
在本人的实际使用中,用这个类管理了
- 子弹
- 子弹碰撞特效
- 攻击特效
- 被攻击特效
- 怪物血条(基于NGUI制作)
- 场景部分文字(施法时、怪物被攻击时,基于NGUI制作)
- 等等。。
欢迎各位进行讨论
《Unity3D》通过对象池模式,管理场景中的元素的更多相关文章
- 对象池模式(Object Pool Pattern)
本文节选自<设计模式就该这样学> 1 对象池模式的定义 对象池模式(Object Pool Pattern),是创建型设计模式的一种,将对象预先创建并初始化后放入对象池中,对象提供者就能利 ...
- GoLang设计模式06 - 对象池模式
这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...
- java设计模式之实现对象池模式示例分享
http://www.jb51.net/article/46941.htm 对象池模式经常用在频繁创建.销毁对象,且对象创建.销毁开销很大的场景,比如数据库连接池.线程池.任务队列池等.本代码简单,没 ...
- 对象池在 .NET (Core)中的应用[2]: 设计篇
<编程篇>已经涉及到了对象池模型的大部分核心接口和类型.对象池模型其实是很简单的,不过其中有一些为了提升性能而刻意为之的实现细节倒是值得我们关注.总的来说,对象池模型由三个核心对象构成,它 ...
- 游戏开发设计模式之对象池模式(unity3d 示例实现)
前篇:游戏开发设计模式之命令模式(unity3d 示例实现) 博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 原理:从一个固定 ...
- 对象池在 .NET (Core)中的应用[1]: 编程体验
借助于有效的自动化垃圾回收机制,.NET让开发人员不在关心对象的生命周期,但实际上很多性能问题都来源于GC.并不说.NET的GC有什么问题,而是对象生命周期的跟踪和管理本身是需要成本的,不论交给应用还 ...
- [Unity3D]Unity3D游戏开发之在3D场景中选择物体并显示轮廓效果
大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei. 在<仙剑奇侠传>.<古剑奇谭>等游戏中,常常须要玩家在一个3D场景中 ...
- Unity3D NGUI制作的Button放到场景中,按钮从2D变到3D
通常我们使用Button都是在UI界面,即NGUI的摄像机下,如果想换到场景中,即不让按钮以UI形式显现,而是和场景中的物体一起随着摄像机移动而缩小,放大. 很简单,把Button从NGUi的摄像机中 ...
- python对象池模式
class QueueObject(): def __init__(self, queue, auto_get=False): self._queue = queue self.object = se ...
随机推荐
- 使用CAtlRegExp类进行密码校验
前言 最近做了一个小需求,新建用户时输入的密码必须包含数字.小写字母.大写字符以及特殊字符,目的是为了增强密码的强度,如果没有其中一项,就需要弹出窗口进行提示. 正则表达式 对于此类 ...
- MyEclipse10.6 安装SVN插件方法及插件下载地址
今天MyEclipse10.6出了点问题,所以重装了它,同一时候也把svn的插件重装了一次,把网上资源和自己的经历顺便在博客这里记录一下.建议直接看方法一好了,简单方便,不必要折腾太多. 下来 ...
- iOS开发之--改变系统导航的颜色,字体,还有返回样式的自定义
在写项目的工程中,我们可能会遇到各种各样的项目,写的方法也是各有不同,不喜欢自定义的小伙伴也很多, 下面我就记录下系统导航和barbuttonitem的修改系统空间的方法: 1,添加rightbarb ...
- shell脚本学习总结08--比较与测试
程序中流程控制是由比较语句和测试语句处理的 算数比较 [ $var -gt 20 ] [ $var -gt 20 -a $var -lt 50 ] #使用逻辑与 [ $var -ne ...
- JS如何获取url查询字符串的键和值?
/** * 根据url查询字符串里的键名获取其值 */function getSearchString(key, search) { // 获取URL中?之后的字符 var str = search; ...
- PHP mysql基本语句指令
/*选择数据库 use test; */ /* 显示所有的数据库 show databases; */ /*删除表/数据库 drop database test1; delete from user1 ...
- 记一个在docker中运行多线程event_loop.run_forever()的bug
问题简介 我写爬虫,用到了asyncio相关的事件循环,新建了一个线程去run_forever(),在docker中运行.后来程序有异常,主线程挂了,但是竟然不报错.查了很久,才找出来. 如果你新建一 ...
- MyBatis笔记——EhCache二级缓存
介绍 ehcache是一个分布式缓存框架. 我们系统为了提高系统并发,性能.一般对系统进行分布式部署(集群部署方式) 不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统开发.所以要使用分布式缓 ...
- Maven 构建Spring-Boot工程报错
Execution default of goal org.springframework.boot:spring-boot-maven-plugin:1.5.6.RELEASE:repackage ...
- python--常用的十进制、16进制、字符串、字节串之间的转换
进行协议解析时,总是会遇到各种各样的数据转换的问题,从二进制到十进制,从字节串到整数等等 整数之间的进制转换: 10进制转16进制: hex(16) ==> 0x10 16进制转10进制 ...