前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐

在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实现”对象池管理器“的更多相关文章

  1. Unity——对象池管理

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

  2. Unity中对象池的使用

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

  3. cocos2D-x 3.5 引擎解析之--引用计数(Ref),自己主动释放池(PoolManager),自己主动释放池管理器( AutoreleasePool)

    #include <CCRef.h> Ref is used for reference count manangement. If a classinherits from Ref. C ...

  4. Unity3D 游戏开发构架篇 —— 动态大场景生成 = 区域加载+对象池管理

    项目做一个类似无尽模式的场景,想了一想,其实方法很简单,做一个相关的总结. 主要先谈一谈构架,后期附上代码. 一.区域加载 其实无尽场景的实现很简单,因为屏幕限制,那么不论何时何地,我们只能看到自己的 ...

  5. Unity对象池管理

    链接: http://www.xuanyusong.com/archives/2925 http://www.xuanyusong.com/archives/2974 https://www.cnbl ...

  6. 使用java自带线程池管理器demo

    1.程序入口:DabianTest package com.lbh.myThreadPool.present; import java.util.concurrent.ExecutorService; ...

  7. Unity3d对象池

    Singleton.cs 12345678910111213 using UnityEngine;/// <summary>/// 单例模版类/// </summary>pub ...

  8. cocos2dx3.0 对象池

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdzE4NzY3MTA0MTgz/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  9. Unity 游戏框架搭建 (二十) 更安全的对象池

    上篇文章介绍了,只需通过实现IObjectFactory接口和继承Pool类,就可以很方便地实现一个SimpleObjectPool.SimpleObjectPool可以满足大部分的对象池的需求.而笔 ...

随机推荐

  1. 微信小程序开发快速入手

    1.在page中的修改数据的setData函数,需要传递的是一个对象. that.setData({ src: res.tempFilePath }) 2.在 onload 事件中,可以获取wx.na ...

  2. throws子句在继承当中overrride时有什么规则

    8.throws子句在继承当中overrride时的规则 马克-to-win:当子类方法override父类方法时,throws子句不能引进新的checked异常.换句话说:子类override方法的 ...

  3. PAT B1086 就不告诉你

    题目描述: 做作业的时候,邻座的小盆友问你:"五乘以七等于多少?"你应该不失礼貌地围笑着告诉他:"五十三."本题就要求你,对任何一对给定的正整数,倒着输出它们的 ...

  4. C++STL 中的数值算法(iota、accumulate、adjacent_difference、inner_product、partial_sum)

    以下算法均包含在头文件 numeric 中 ##1.iota 该函数可以把一个范围内的序列从给定的初始值开始累加 先看用法. 例: 假设我需要一个长度为10,从5开始递增的序列 vector<i ...

  5. 帝国cms 7.5版列表页分页样式修改笔记

    最近在用帝国改版我的个人博客站点,这个也是我第一次尝试用帝国来做博客,之前用过wordpress,每用一个新的程序,都会有些新的收获,也会学到一些新的东西. 在改用帝国之前,我也在网上大概了解了一下, ...

  6. C++内存空间管理

    C++内存空间管理 1.C++内存机制 1.栈(Stack),函数中的局部变量,由编译器负责分配释放,函数结束,变量释放. 2.堆(Heap),通过new 申请的内存,由delete或delete[] ...

  7. 挖矿病毒分析(centos7)

    因为我在工作的时候被各种挖矿病毒搞过几次,所以在这里整理下我遇到的病毒以及大神们的解决方案. 服务器中挖矿病毒后,最基本的一个特征就是CPU使用率瞬间飙升,此时可以通过top命令进行查看,确认是否有异 ...

  8. c#中判断类是否继承于泛型基类

    在c#中,有时候我们会编写类似这样的代码: public class a<T> { //具体类的实现 } public class b : a<string>{} 如果b继承a ...

  9. docker进阶_docker-compose

    Docker-compose 为什么使用docker-compose 官方介绍 ​ Compose 是一个用于定义和运行多容器 Docker 应用程序的工具.使用 Compose,您可以使用 YAML ...

  10. nodejs mysql pool 只能插入10条记录或者较少记录

    BEGIN; 解决方案:从连接池获取到的Connection,执行完操作后,必须及时关闭! 即:connection.end(); 使用后发现console有打印出警告信息,大致意思为 end() 方 ...