对象池这个名字听起来好像不明觉厉,其实就是将一系列需要反复创建和销毁的对象存储在一个看不到的地方,下次用同样的东西时往这里取,类似于一个存放备用物质的仓库。

它的好处就是避免了反复实例化个体的运算,能减少大量内存碎片,当然你需要更多的空间来存这些备用对象,相信使用这些空间是非常值得的。

最常见的应用就是子弹的创建和销毁。

一般对象池都是一个全局性的通用脚本,可以采用单例模式来设计。

https://www.cnblogs.com/koshio0219/p/11203631.html

对象池至少包含以下两个基本功能:

1.从池中取出指定类型的对象

2.回收各式各样的对象到池中

先定义对象池和池子的容量:

     private const int maxCount = ;
private Dictionary<string, List<GameObject>> pool = new Dictionary<string, List<GameObject>>();

容量是一个常量,最好取二的幂值,这样的话可以刚好占用所有内存位的资源,避免浪费。

这里池子用字典标识,key为对象的名字,这样比较好记,你用InstanceID也没问题。

每个同样的对象一般在池子中可以有很多,用一个List来存。

下面先定义回收对象的方法:

     public void RecycleObj(GameObject obj)
{
var par = Camera.main;
obj.transform.SetParentSafe(par.transform);
obj.SetActive(false); if (pool.ContainsKey(obj.name))
{
if (pool[obj.name].Count < maxCount)
{
pool[obj.name].Add(obj);
}
}
else
{
pool.Add(obj.name, new List<GameObject>() { obj });
}
}

这里将回收的对象统一放在了场景主摄像机下,你也可以选择放在自己喜欢的位置。

回收对象就是先把对象隐藏,然后看池子中有没有这一类对象,有的话没有超过容量上限就直接扔进去。

如果没有这类对象,那就创建这一类型对象的Key值(名字:比如说螃蟹),顺便添加第一只螃蟹。

如果回收对象时改变了父物体,最好在设置父物体前后记录下对象的本地位置,旋转和缩放,可以写了一个扩展方法用于安全设置父物体:

     public static void SetParentSafe(this Transform transform,Transform parent)
{
var lp = transform.localPosition;
var lr = transform.localRotation;
var ls = transform.localScale;
transform.SetParent(parent);
transform.localPosition = lp;
transform.localRotation = lr;
transform.localScale = ls;
}

经常会遇到要批量回收进池子的情况:

     public void RecycleAllChildren(GameObject parent)
{
for (; parent.transform.childCount > ;)
{
var tar = parent.transform.GetChild().gameObject;
RecycleObj(tar);
}
}

对象可以回收了,那怎么取呢,自然也是能从池子里取就从池子里取,实在不行才去实例化:

     public GameObject GetObj(GameObject perfab)
{
//池子中有
GameObject result = null;
if (pool.ContainsKey(perfab.name))
{
if (pool[perfab.name].Count > )
{
result = pool[perfab.name][];
result.SetActive(true);
pool[perfab.name].Remove(result);
return result;
}
}
//池子中缺少
result = Object.Instantiate(perfab);
result.name = perfab.name;
RecycleObj(result);
GetObj(result);
return result;
}

如果池子中有对象,取出来之后记得要把这个对象从该类对象的列表中移除,不然下次可能又会取到这家伙,而这家伙已经要派去做别的了。

如果池子中缺少对象,那就只能实例化了,要注意把实例化后的对应改为大家都一样的名字,这样方便下一次取能找到它。

没有对象的情况下,我这里又重新回收了一下再取一次,你也可以直接返回该对象,相当于在取的时候不存在这类对象的话我提前做了标记。

和Instantiate方法一样,加一个可以设置父对象的重载方法:

     public GameObject GetObj(GameObject perfab, Transform parent)
{
var result = GetObj(perfab);
result.transform.SetParentSafe(parent);
return result;
}

下面是完整脚本:

 using System.Collections.Generic;
using UnityEngine; public class ObjectPool : Singleton<ObjectPool>
{
private const int maxCount = ;
private Dictionary<string, List<GameObject>> pool = new Dictionary<string, List<GameObject>>(); public GameObject GetObj(GameObject perfab)
{
//池子中有
GameObject result = null;
if (pool.ContainsKey(perfab.name))
{
if (pool[perfab.name].Count > )
{
result = pool[perfab.name][];
if (result != null)
{
result.SetActive(true);
pool[perfab.name].Remove(result);
return result;
}
else
{
pool.Remove(perfab.name);
}
}
}
//池子中缺少
result = Object.Instantiate(perfab);
result.name = perfab.name;
RecycleObj(result);
GetObj(result);
return result;
} public GameObject GetObj(GameObject perfab, Transform parent)
{
var result = GetObj(perfab);
result.transform.SetParentSafe(parent);
return result;
} public void RecycleObj(GameObject obj)
{
var par = Camera.main;
obj.transform.SetParentSafe(par.transform);
obj.SetActive(false); if (pool.ContainsKey(obj.name))
{
if (pool[obj.name].Count < maxCount)
{
pool[obj.name].Add(obj);
}
}
else
{
pool.Add(obj.name, new List<GameObject>() { obj });
}
} public void RecycleAllChildren(GameObject parent)
{
for (; parent.transform.childCount > ;)
{
var tar = parent.transform.GetChild().gameObject;
RecycleObj(tar);
}
} public void Clear()
{
pool.Clear();
}
}

因为是用名字作为存储的Key值,所以不同类的物体命名不能相同,不然可能会取错对象。

另外由于上面的脚本有更改父物体的情况,在取出物体之后根据需要也可以对transform进行归位:

     public static void ResetLocal(this Transform transform)
{
transform.localPosition = Vector3.zero;
transform.localRotation = Quaternion.identity;
transform.localScale = Vector3.one;
}

上面是对Transform类的一个扩展方法,例如:

  var ins = ObjectPool.Instance.GetObj(bulletPrefab, parent.transform);
ins.transform.ResetLocal();

游戏设计模式——Unity对象池的更多相关文章

  1. Unity——对象池管理

    Unity对象池管理 一.Demo展示 二.逻辑 在游戏中会出现大量重复的物体需要频繁的创建和销毁:比如子弹,敌人,成就列表的格子等: 频繁的创建删除物体会造成很大的开销,像这种大量创建重复且非持续性 ...

  2. Unity 对象池 生产 保存

    Unity对象池主要是保存那些常用的物体,避免他们在不断销毁和创造中损坏性能. 主要思路为:创造物体时,判断是否存在,如果存在则调用并使其显示.如果不存在则创造一个新的. 当销毁时,调用协程延时隐藏物 ...

  3. 游戏开发设计模式之对象池模式(unity3d 示例实现)

    前篇:游戏开发设计模式之命令模式(unity3d 示例实现) 博主才学尚浅,难免会有错误,尤其是设计模式这种极富禅意且需要大量经验的东西,如果哪里书写错误或有遗漏,还请各位前辈指正. 原理:从一个固定 ...

  4. unity游戏开发_对象池

    现在假设游戏中我们需要实现一个这样功能,按下鼠标左键,发射一颗子弹,3秒之后消失.在这个功能中,我们发射了上百上千发子弹,就需要实例化生成上百上千次.这时候,我们就需要使用对象池这个概念,每次实例化生 ...

  5. Unity ----- 对象池GameObjectPool

    孙广东 2014.6.28 非常早之前看到的外国文章,认为不错,分享一下. 对象池在AssetStore中也是有非常多插件的,可是有些重了.自己写一个轻量的岂不是非常好. 当你须要创建大量某种类型对象 ...

  6. Unity 对象池的使用

    在游戏开发过程中,我们经常会遇到游戏发布后,测试时玩着玩着明显的感觉到有卡顿现象.出现这种现象的有两个原因:一是游戏优化的不够好或者游戏逻辑本身设计的就有问题,二是手机硬件不行.好吧,对于作为程序员的 ...

  7. Unity对象池的实现

    对象池是一个单例类: using System.Collections; using System.Collections.Generic; using UnityEngine; public cla ...

  8. GoLang设计模式06 - 对象池模式

    这次介绍最后一个创建型模式--对象池模式.顾名思义,对象池模式就是预先初始化创建好多个对象,并将之保存在一个池子里.当需要的时候,客户端就可以从池子里申请一个对象使用,使用完以后再将之放回到池子里.池 ...

  9. 游戏设计模式——Unity事件队列(纪念京阿尼事件)

    “对消息或事件的发送与受理进行时间上的解耦.” 在游戏开发过程中,经常会出现不同板块之间的信息交流,或是存在“当...,就...”的情况,事件队列编程模式可以有效解决消息传递中产生的脚本耦合问题,让同 ...

随机推荐

  1. Go语言框架:Beego vs Gin 的区别

    前言: 一切语言.技术或者框架,本质都是工具,工具的价值在于为使用者提供竞争优势. 一.Beego和Gin全方位比较 MVC Beego支持完整的MVC, Gin不支持完整的MVC(需要开发者自己实现 ...

  2. MySQL里的COUNT

    count(*).count(1).count(主键).count(字段)的执行效率 在没有where条件的情况下 MyISAM引擎返回结果会比InnoDB快上很多,主要是因为MyISAM会单独记录了 ...

  3. 线程学习oneday

    进程:执行中的程序叫做进程(Process),是一个动态的概念. 线程:一个进程可以产生多个线程.同多个进程可以共享操作系统的某些资源一样,同一进程的多个线程也可以共享此进程的某些资源(比如:代码.数 ...

  4. Eclipse配置初始化(自用)

    以上都是性能调优的配置,下面是其他常用的配置和优化 设置utf-8编码 window -> preferences -> General -> workplace中text file ...

  5. HuffmanTree

    /* 例如,对于数列{pi}={5, 3, 8, 2, 9},Huffman树的构造过程如下: 1. 找到{5, 3, 8, 2, 9}中最小的两个数,分别是2和3,从{pi}中删除它们并将和5加入, ...

  6. python 14 装饰器

    目录 装饰器 1. 开放封闭原则 装饰器 1. 开放封闭原则 扩展是开放的,增加新的功能:修改源码(修改已经实现的功能)是封闭的. 在不改变源码及调用方式的前提下额外增加新的功能. # 版一: imp ...

  7. 替代Flume——Kafka Connect简介

    我们知道过去对于Kafka的定义是分布式,分区化的,带备份机制的日志提交服务.也就是一个分布式的消息队列,这也是他最常见的用法.但是Kafka不止于此,打开最新的官网. 我们看到Kafka最新的定义是 ...

  8. Java集合框架之HashMap浅析

    Java集合框架之HashMap浅析 一.HashMap综述: 1.1.HashMap概述 位于java.util包下的HashMap是Java集合框架的重要成员,它在jdk1.8中定义如下: pub ...

  9. Mybatis与SQL Server类型转换遇到的坑

    一. MyBatis SQL语句遇到的性能问题 1. 场景还原 假设我们有一张User表,其中包含userId.userName.gender字段,其中userId的数据类型为char(20),此时我 ...

  10. 《GO Home Trash!》UML类图,ER图以及数据库设计

    <Go Home Trash!>UML类图 ER图以及数据库中数据表 分析: 这款软件经过我们前期的讨论以及需求分析,确定了用户,客服以及管理员三个实体.在设计UML类图时,对各个实体之间 ...