Unity对象池管理

一、Demo展示

二.逻辑

在游戏中会出现大量重复的物体需要频繁的创建和销毁;比如子弹,敌人,成就列表的格子等;

频繁的创建删除物体会造成很大的开销,像这种大量创建重复且非持续性保持作用的对象我们会使用对象池将其管理起来,用空间换效率;

对象池的要对外提供创建销毁对象的接口,已经添加对象池的接口;

对内要提供创建对象,根据路径查找预制的接口;

整体逻辑如下:

二.加载/添加对象池

添加资源路径,分为Resources文件夹下和SteamingAssets文件下资源;

Resources加载时路径不需要后缀,SteamingAssets需要后缀,根据path路径开头的判断加载方式,同时对路径做处理;

SteamingAssets需要根据平台添加路径头Application.streamingAssetsPath;

Resources需要去掉格式后缀,如.perfab;

这里我测试只使用Resources路径,正式项目自行处理;

存放预创建好的对象:

private Dictionary<string,List<GameObject>> pool;

存放预制体路径:

private Dictionary<string, string> objPath;
public void InitPath()
{
//测试用,正常肯定要做字符串处理的,需要加后缀
objPath.Add("cube","Cube");
objPath.Add("sphere","Sphere");
}
public void Add(string key, int num)
{
if (pool.ContainsKey(key))
{
for (int i = 0; i < num; ++i)
{
//AssetBundle ab = AssetBundle.LoadFromFile($"{path}/{objPath[key]}");
//GameObject go = Instantiate(ab.LoadAsset<GameObject>(key));
//由于我的测试资源就放在Resources下,正式项目需要根据路径做个判断;
GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key]));
go.SetActive(false);
pool[key].Add(go);
}
}
else
{
List<GameObject> goList = new List<GameObject>();
pool.Add(key, goList); for (int i = 0; i < num; ++i)
{
//AssetBundle ab = AssetBundle.LoadFromFile(objPath[key]);
//GameObject go = Instantiate(ab.LoadAsset<GameObject>(key));
GameObject go = Instantiate(Resources.Load<GameObject>(objPath[key]));
go.SetActive(false);
pool[key].Add(go);
}
}
}

三.管理对象池

对象池管理需要对外提供创建对象,销毁对象,延迟销毁和清空池的方法;

创建对象时,需要提供key,坐标,旋转;

现查找是否有对象池,没有则添加;

这里提供了四元素和欧拉角的重载方法;

1.创建对象

public GameObject FindUsable(string key
{
if(pool.ContainsKey(key))
{
foreach (GameObject item in poo
{
if (!item.activeSelf)
return item;
}
Debug.Log($"{key}的对象池数量不够");
}
else
{
Debug.Log($"{key}未添加对象池");
}
return null;
}
/// <summary>创建一个游戏物体到场景 </summary>
public GameObject CreateObject(string k
{
GameObject tempGo = FindUsable(key)
if (tempGo == null)
{
Debug.Log($"{key}的对象池数量不够");
Add(key, 10);
tempGo = FindUsable(key);
}
tempGo.transform.position = positio
tempGo.transform.rotation = quatern
tempGo.SetActive(true);
return tempGo;
}
public GameObject CreateObject(string k
{
GameObject tempGo = FindUsable(key)
if (tempGo == null)
{
Debug.Log($"{key}的对象池数量不够");
Add(key, 10);
tempGo = FindUsable(key);
}
tempGo.transform.position = positio
tempGo.transform.rotation = Quatern
tempGo.SetActive(true);
return tempGo;
}

2.销毁对象

延时销毁可使用回调(invoke)或协程;

public void Destory(GameObject destoryGo)
{
destoryGo.SetActive(false);
} /// <summary>将对象归入池中<summary>
public void Destory(GameObject tempGo, float delay)
{
StartCoroutine(DelayDestory(tempGo,delay));
}
/// <summary>延迟销毁</summary>
private IEnumerator DelayDestory(GameObject destoryGO, float delay)
{
yield return new WaitForSeconds(delay);
Destory(destoryGO);
}

3.清空池

/// <summary>清空某类游戏对象</summary>
public void Clear(string key)
{
pool.Remove(key);
}
/// <summary>清空池中所有游戏对象</summary>
public void ClearAll()
{
pool.Clear();
}

四、测试代码

两个按钮分别创建方块和球,每次创建更改一次位置;鼠标射线点击延迟1s销毁;

public class Test : MonoBehaviour
{
public Button btnCube;
public Button btnSphere;
void Start()
{
GameObjectPool.I.InitPath();
GameObjectPool.I.Add("cube",10);
GameObjectPool.I.Add("sphere",10);
btnCube.onClick.AddListener(OnBtnCube);
btnSphere.onClick.AddListener(OnBtnSphere);
} private Vector3 deltaPos = new Vector3(1, 1, 1);
private Vector3 pos =new Vector3(-10,0,0);
private void OnBtnCube()
{
GameObject go = GameObjectPool.I.CreateObject("cube", pos, Vector3.zero); go.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1"));
go.transform.position += deltaPos;
pos = go.transform.position;
} private Vector3 pos1 =new Vector3(0,0,0);
private void OnBtnSphere()
{
GameObject go = GameObjectPool.I.CreateObject("sphere", pos1, Vector3.zero); go.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(go, SceneManager.GetSceneByName("1"));
go.transform.position += deltaPos;
pos1 = go.transform.position;
} private void Update()
{
if(Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if(Physics.Raycast(ray,out hitInfo)){
Debug.DrawLine(ray.origin,hitInfo.point);
GameObject gameObj = hitInfo.collider.gameObject;
Debug.Log("click object name is " + gameObj.name);
GameObjectPool.I.Destory(gameObj,1);
}
}
}
}

Unity——对象池管理的更多相关文章

  1. Unity对象池管理

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

  2. Unity 对象池 生产 保存

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

  3. Unity实现”对象池管理器“

    前言:警告!这可能是坨屎,空闲时间写成,仅作娱乐 在Unity中生成或销毁一个物体会占用较大的资源,如果是制作FPS射击游戏,子弹生成更是雪上加霜.所以我自己写了一个PoolManager,不能和网上 ...

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

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

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

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

  6. Unity 对象池的使用

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

  7. Unity对象池的实现

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

  8. 游戏设计模式——Unity对象池

    对象池这个名字听起来很玄乎,其实就是将一系列需要反复创建和销毁的对象存储在一个看不到的地方,下次用同样的东西时往这里取,类似于一个存放备用物质的仓库. 它的好处就是避免了反复实例化个体的运算,能减少大 ...

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

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

随机推荐

  1. HTML基本语法(慕课网学习笔记)

    标题 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8& ...

  2. 分布式链路追踪系统Sleuth和ZipKin

    1.微服务下的链路追踪讲解和重要性 简介:讲解什么是分布式链路追踪系统,及使用好处 进行日志埋点,各微服务追踪. 2.SpringCloud的链路追踪组件Sleuth 1.官方文档 http://cl ...

  3. Java中除数为0的情况

    转自http://blog.csdn.net/alanzyy/article/details/8591534 在数学中,规定被除数不能为0 那么在Java程序中一旦出现除数为0时,会出现什么情况呢: ...

  4. kubebuilder实战之五:operator编码

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. springboot全局异常封装案例

    @ControllerAdvice三个场景:>https://www.cnblogs.com/lenve/p/10748453.html 全局异常处理 全局数据绑定 全局数据预处理 首先定义一个 ...

  6. 利用元数据提高 SQLFlow 血缘分析结果准确率

    利用元数据提高 SQLFlow 血缘分析结果准确率 一.SQLFlow--数据治理专家的一把利器 数据血缘属于数据治理中的一个概念,是在数据溯源的过程中找到相关数据之间的联系,它是一个逻辑概念.数据治 ...

  7. Ubuntu 设置不更新某些软件

    方法来自:https://blog.csdn.net/zhrq95/article/details/79527073 保持某软件版本不变,如我wps-office,(已测有效@Ubuntu 16.04 ...

  8. 并发编程之:AQS源码解析

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 在Java并发编程中,经常会用到锁,除了Synchronized这个JDK关键字以外,还有Lock接口下面的各种锁实现,如重入锁ReentrantLo ...

  9. 单片机学习(十二)1-Wire通信协议和DS18B20温度传感器

    目录 一.DS18B20 1. DS18B20简介 2. 电路原理图 3. 内部结构 内部完整结构框图 存储器结构 二.单总线(1-Wire BUS) 1. 单总线简介 2. 电路规范 3. 单总线的 ...

  10. poll?transport=longpoll&connection...烦人的请求c

    1.问题描述: 最近使用miniui做了一个后台管理系统,打开浏览器调试时,总发现一堆无关的请求,结构大致是:poll?transport=longpoll&connection.....一直 ...