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

在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. 纹理集打包和动画转换工具Texture Merge的使用教程

    Texture Merger 可将零散纹理拼合为整图,同时也可以解析SWF.GIF动画,制作Egret位图文本,导出可供Egret使用的配置文件,其纹理集制作功能在小游戏开发中可以起到降低小游戏包体的 ...

  2. 异步任务-springboot

    异步任务-springboot 异步:异步与同步相对,当一个异步过程调用发出后,调用者在没有得到结果之前,就可以继续执行后续操作.也就是说无论异步方法执行代码需要多长时间,跟主线程没有任何影响,主线程 ...

  3. linux部署项目访问mysql问题

    springboot以war包形式传到webapps下面,mysql创建库和表,war包里配置数据源是localhost,然后运行tomcat是没有问题的,可以访问通mysql正常请求服务. ssm以 ...

  4. 【图文教学】如何轻松下载tiktok上的视频

    我是真诚的想和大家分享这个办法的!这个叫光影存图,图标就是这个绿色的箭头,我是苹果手机,安卓手机也可以用,就是它分免费版和会员版的,没有强制要你充会员,看一下广告就可以获取下载次数,我就是这么干的,只 ...

  5. Ant Design Pro V5 与 IdentityServer 实现 Password 模式的登录

    最近处于休息状态,想趁着休息时间,为自己做一个后台. 后端框架选用了 Abp.之前公司使用了一些自研的框架,但由于人力资源有限,后期框架的升级及维护都是比较耗时,这次干脆直接使用Abp,即省心又能快速 ...

  6. vue 修改单页标题 --- document.title

    方法1. 在需要的组件或者页面内设置 document.title = response.data.res.title 方法2. <head> <meta http-equiv=&q ...

  7. Python识别图片中的文字

    1 import os,glob 2 def photo_compression(original_imgage,tmp_image_path): 3 '''图片备份.压缩:param origina ...

  8. .net core 配置swagger

    首先要现有一个asp.net  webApi项目 这里就不赘述了,接下来就按下面的步骤进行即可(本文是基于swagger 1.0.0-rc3版本的配置) 1.在project.json中添加 swag ...

  9. 聊聊Lock接口的lock()和lockInterruptible()有什么区别?

    lock()和lockInterruptible()都表示获取锁,唯一区别是,当A线程调用lock()或lockInterruptible()方法获取锁没有成功而进入等待锁的状态时,若接着调用该A线程 ...

  10. docker:compose实战

    1.用docker-compose拉起三个容器:nginx->ghost博客平台->mysql,拉起后可以直接访问ghost博客平台 2.目录结构: ghost: data docker- ...