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可以满足大部分的对象池的需求.而笔 ...
随机推荐
- js随手笔记-------理解JavaScript碰撞检测算法核心简单实现原理
碰撞检测在前端游戏,设计拖拽的实用业务等领域的应用场景非常广泛,今天我们就在这里对于前端JavaScript如何实现碰撞检测算法进行一个原理上的探讨,让大家能够明白如何实现碰撞以及碰撞的理念是什么:1 ...
- 体温登记app开发流程
关于体温app,比较难的是获取定位信息,剩下的就是增删改查. 设计思路:首先布局一个添加页面,给每个元件添加id,之后在获取地点的EditText获取位置信息,在添加两个布局文件,体现在一个页面里用来 ...
- hdfs对文件的增删改查
源代码: pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&qu ...
- 存储过程 psal emp.sal%type是什么意思
psal emp.sal%type 就是指psal这个变量是引用了表emp中的sal字段的类型.如果emp表中sal的类型变了,psal这个字段的类型也会跟着变化,总之,psal和表emp中sal字段 ...
- Django高级之-缓存
一 缓存介绍 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消 ...
- 将mysql主从复制由ABB模式修改为ABC模式
最近遇到一个奇葩的需求,需要将mysql的主从复制模式由ABB修改为ABC,恰好这个mysql集群没有开启GTID,当时是在B上做了一次全量备份,然后使用该全量备份恢复C的方式进行的.做完之后在想有没 ...
- 2021.08.03 P1197 星球大战(并查集)
2021.08.03 P1197 星球大战(并查集) [P1197 JSOI2008]星球大战 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.可以离线处理.把在线变为离 ...
- vite初使用随记
vite的安装 按照官网文档来看,并不难. 先检查自己电脑node的版本与npm的版本/yarn的版本 可以直接用yarn安装,yarn create vite 这是最原始的安装,即类似于安装vue- ...
- 技术管理进阶——一线Leader怎么做?经理的速成宝典
原创不易,求分享.求一键三连 本期培训材料关注公众号后回复:经理培训,获得 前段时间有个同学问我有没有一线Leader的速成培训课程,很好的问题,首先我们需要定义一下什么是小Leader: 所谓小Le ...
- java中的stream是啥?
函数式编程的执行是惰性的,按顺序真正执行的时候才会执行相应的代码.方法: 函数式编程是安全的,用的是monad架构 1 public class StreamTest { 2 3 public sta ...