Unity实现”对象池管理器“
前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐
在Unity中生成或销毁一个物体会占用较大的资源,如果是制作FPS射击游戏,子弹生成更是雪上加霜。所以我自己写了一个PoolManager,不能和网上的各位大佬作比较,仅作娱乐。
该实例主要是通过一个PoolUtil对象作为一类游戏的对象池,再通过PoolManager来管理诸多PoolUtil。
PoolUtil的功能,主要还是靠队列实现的。调用者每次”销毁“物体时,将物体放入池中,并隐藏起来。再次生成时,查看池中有无待用的物体,若有则直接显示出来。若无,则继续生成新物体。
public class PoolUtil:MonoBehaviour
{
public GameObject prefab;
public string poolName;
public Queue<GameObject> queue; /// <summary>
/// 初始化方法
/// </summary>
/// <param name="prefab">要生成的预制体</param>
/// <param name="poolName">池名</param>
/// <param name="preLoadCount">预加载的数量</param>
public void Init(GameObject prefab,string poolName, int preLoadCount)
{
queue = new Queue<GameObject>();
this.prefab = prefab;
gameObject.name = "PoolUtil_" + poolName;
this.poolName = poolName;
PreLoad(preLoadCount);
} /// <summary>
/// 预加载方法
/// </summary>
/// <param name="preLoadCount">预加载数量</param>
void PreLoad(int preLoadCount)
{
for (int i = preLoadCount; i > 0; i--)
{
GameObject newObj = Instantiate(prefab);
newObj.SetActive(false);
SetGameObject(newObj.transform,GameObject.Find("Canvas").transform);
queue.Enqueue(newObj);
}
} /// <summary>
/// 生成方法
/// </summary>
/// <param name="pos">生成位置</param>
/// <param name="rotation">生成时的旋转度数</param>
/// <param name="parent">生成物体的父物体</param>
/// <returns>返回生成的物体</returns>
public GameObject Spawn(Vector3 pos,Quaternion rotation,Transform parent)
{
GameObject newObj = null;
if (queue.Count!=0)
{
newObj = queue.Dequeue();
newObj.SetActive(true);
SetGameObject(newObj.transform, pos, rotation, parent);
return newObj;
} newObj = Instantiate(prefab);
SetGameObject(newObj.transform, pos, rotation, parent);
return newObj;
} /// <summary>
/// ”销毁“物体
/// </summary>
/// <param name="obj">要销毁的目标游戏物体</param>
public void DeSpawn(GameObject obj)
{
obj.SetActive(false);
queue.Enqueue(obj);
} /// <summary>
/// 设置物体的位置旋转和父物体
/// </summary>
/// <param name="obj"></param>
/// <param name="pos"></param>
/// <param name="rotation"></param>
/// <param name="parent"></param>
private void SetGameObject(Transform obj,Vector3 pos,Quaternion rotation,Transform parent)
{
obj.SetParent(parent);
obj.localRotation = rotation;
obj.localPosition = pos;
}
/// <summary>
/// 下面三个是重载
/// </summary>
/// <param name="obj"></param>
/// <param name="rotation"></param>
/// <param name="parent"></param>
private void SetGameObject(Transform obj,Quaternion rotation,Transform parent)
{
obj.SetParent(parent);
obj.localRotation = rotation;
obj.localPosition = Vector3.zero;
}
private void SetGameObject(Transform obj,Vector3 pos,Transform parent)
{
obj.SetParent(parent);
obj.localRotation = Quaternion.identity;
obj.localPosition = pos;
}
private void SetGameObject(Transform obj,Transform parent)
{
obj.SetParent(parent);
obj.localRotation = Quaternion.identity;
obj.localPosition = Vector3.zero;
}
}
public class PoolManager : MonoBehaviour
{
private Dictionary<string, PoolUtil> poolDic;
public static PoolManager Instance; private void Start()
{
//单例模式好调用
Instance = this;
DontDestroyOnLoad(gameObject);
poolDic = new Dictionary<string, PoolUtil>();
} /// <summary>
/// 暴露给调用者的生成方法
/// </summary>
/// <param name="needPool">是否需要生成池</param>
/// <param name="prefab">要生成的物体</param>
/// <param name="pos">位置</param>
/// <param name="rotation">旋转</param>
/// <param name="parent">父物体</param>
public void CreateObj(bool needPool,GameObject prefab,Vector3 pos,Quaternion rotation,Transform parent)
{
if (needPool)//需要对象池
{
QueryPool(prefab).Spawn(pos,rotation,GameObject.Find("Canvas").transform);
}
else
{
GameObject temp = Instantiate(prefab);
temp.transform.SetParent(parent);
temp.transform.localPosition = pos;
temp.transform.localRotation = rotation;
}
} /// <summary>
/// 暴露给调用者的“销毁”方法
/// </summary>
/// <param name="deleteObj">销毁的目标物体</param>
public void DestroyObj(GameObject deleteObj)
{
QueryPool(deleteObj).DeSpawn(deleteObj);
} /// <summary>
/// 查询字典中有无该物体的池
/// </summary>
/// <param name="prefab">目标物体</param>
/// <returns>返回该物体的池</returns>
private PoolUtil QueryPool(GameObject prefab)
{
string key = prefab.name.Split('(')[0];
if (!poolDic.ContainsKey(key))
{
CreatePool(prefab);
}
return poolDic[key];
} /// <summary>
/// 创建目标物体的池
/// </summary>
/// <param name="prefab">目标物体</param>
private void CreatePool(GameObject prefab)
{
GameObject obj = new GameObject();
PoolUtil util = obj.AddComponent<PoolUtil>();
util.Init(prefab,prefab.name,1);
poolDic.Add(prefab.name, util);
obj.transform.SetParent(transform);
}
}
PoolManager主要通过一个池的字典,每次创建物体时,根据调用者的实际情况,判断是否需要创建池?然后加入到字典。这样,调用者再次创建时,即可查找指定池,并将目标物体放入该池中,方便复用。
下面是测试代码
public class TestPool : MonoBehaviour
{
public GameObject prefab;
public void ButtonFunc()
{
PoolManager.Instance.CreateObj(true,prefab,Vector3.zero,Quaternion.identity,GameObject.Find("Canvas").transform);
}
}
在Unity新建一个Canvas,将该代码添加到Canvas上。新建一张图片改成红色,然后拖拽到Assets下作为预制体。为测试”销毁“功能,另外新建脚本:
public class ImageFunc : MonoBehaviour
{
private float timer = 0;
private float interval = 5f;
void OnEnable()
{
timer = Time.time;
} // Update is called once per frame
void Update()
{
if(Time.time-timer>=interval)
{
PoolManager.Instance.DestroyObj(this.gameObject);
}
}
}
此代码作为预制体自身的脚本,生成时就开始计时,到达五秒后销毁自己。再次生成时会重置时间为当前时间。


关于该对象池的优化方向:
1.可以从Hierachy面板上点击PoolUtil,观察其Insperctor面板,可查询场景中有哪些物体归这个池管?
2.添加功能销毁池本身,如果长时间不再新生成该对象,应该逐步销毁池中物体,直至池中物体数量归0,然后销毁池
目前就想到这么多了
Unity实现”对象池管理器“的更多相关文章
- Unity——对象池管理
Unity对象池管理 一.Demo展示 二.逻辑 在游戏中会出现大量重复的物体需要频繁的创建和销毁:比如子弹,敌人,成就列表的格子等: 频繁的创建删除物体会造成很大的开销,像这种大量创建重复且非持续性 ...
- Unity中对象池的使用
unity中用到大量重复的物体,例如发射的子弹,可以引入对象池来管理,优化内存. 对象池使用的基本思路是: 将用过的对象保存起来,等下一次需要这种对象的时候,再拿出来重复使用.恰当地使用对象池,可以在 ...
- cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)
#include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...
- Unity3D 游戏开发构架篇 —— 动态大场景生成 = 区域加载+对象池管理
项目做一个类似无尽模式的场景,想了一想,其实方法很简单,做一个相关的总结. 主要先谈一谈构架,后期附上代码. 一.区域加载 其实无尽场景的实现很简单,因为屏幕限制,那么不论何时何地,我们只能看到自己的 ...
- Unity对象池管理
链接: http://www.xuanyusong.com/archives/2925 http://www.xuanyusong.com/archives/2974 https://www.cnbl ...
- 使用java自带线程池管理器demo
1.程序入口:DabianTest package com.lbh.myThreadPool.present; import java.util.concurrent.ExecutorService; ...
- Unity3d对象池
Singleton.cs 12345678910111213 using UnityEngine;/// <summary>/// 单例模版类/// </summary>pub ...
- cocos2dx3.0 对象池
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdzE4NzY3MTA0MTgz/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...
- Unity 游戏框架搭建 (二十) 更安全的对象池
上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...
随机推荐
- CentOS 7.9 网络配置
vi /etc/sysconfig/network-scripts/ifcfg-ens33 (45条消息) CentOS 7.9 网络配置_$青的博客-CSDN博客_centos7.9网卡配置
- MySQL8.0官方文档学习
InnoDB架构 下面的架构里只挑选了部分内容进行学习 内存架构(In-Memory Structures) Buffer Pool Buffer Pool是内存中的一块区域,InnoDB访问表和索引 ...
- jdbc连接数据库以及简单实现(普通JDBC方法实现和连接池方式实现)
@ 目录 总结内容 1. 基本概念 jdbc的概念 2. 数据库连接 数据库的连接 DAO层思想 重构设计 3. 事务 概念 事务的ACID属性 事务的操作 4. 连接池 为什么要使用连接池 连接池分 ...
- SLF4J 报错解决:No SLF4J providers were found
1.解决SLF4J报错 我们在自己的项目中使用了SLF4J,或者引入了某开源项目时,他的项目中用了SLF4J,运行时会报如下的错误: SLF4J: Failed to load class " ...
- 帝国cms随机调用信息
我们知道,帝国cms随机调用标签是 [ecmsinfo]1,5,32,0,0,2,0,",'rand()'[/ecmsinfo] 但是这种调用方式在数据量特别大的时候严重影响生成速度,对于中 ...
- 5.Java程序运行机制
一.编译型和解释型语言区别 计算机是不能理解高级语言的,更不能直接执行高级语言,它只能直接理解机器语言,所以任何的高级语言编写的程序都必须转换成计算机语言,也就是机器码.而这种转换的方式有两种: 编译 ...
- nodejs的tream(流)解析与模拟文件读写流源码实现
什么是流? 可读流于可写流 双工流于转换流 背压机制与文件流模拟实现 一.什么是流? 关于流的概念早在1964年就有记录被提出了,简单的说"流"就是控制数据传输过程的程序,比如在那 ...
- Java 获取Word中的所有插入和删除修订
在 Word 文档中启用跟踪更改功能后,会记录文档中的所有编辑行为,例如插入.删除.替换和格式更改.对插入或删除的内容,可通过本文中介绍的方法来获取. 引入Jar 方法1 手动引入:将 Free Sp ...
- Spark SQL底层执行流程详解
本文目录 一.Apache Spark 二.Spark SQL发展历程 三.Spark SQL底层执行原理 四.Catalyst 的两大优化 一.Apache Spark Apache Spark是用 ...
- 0基础学习docker
进入docker容器命令 docker exec -it 容器id bash 获取镜像 # 1.获取镜像,镜像托管仓库 docker search centos # 查询centos镜像 docker ...