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. 【java虚拟机】垃圾回收机制详解

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6486852.html 一.为什么需要垃圾回收 如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分 ...

  2. Kafka源码篇 --- 小白也能看懂的Producer的初始化及元数据获取流程

    最近在研究kafka的源码,发现有些小伙伴的源码写的很不错,就想转载一下,让更多的人知道和学习一下. https://blog.csdn.net/weixin_43167418/article/det ...

  3. win命令

    netstat -nao | findstr "8888"taskkill /pid 15064 /f清理端口被占用win+r进入cmdcmd窗口中输入notepad进入记事本sh ...

  4. LeetCode入门指南 之 动态规划思想

    推荐学习labuladong大佬的动态规划系列文章:先弄明白什么是动态规划即可,不必一次看完.接着尝试自己做,没有思路了再回过头看相应的文章. 动态规划一般可以由 递归 + 备忘录 一步步转换而来,不 ...

  5. Adaptive AUTOSAR 学习笔记 16 - 时间同步和网络管理

    本系列学习笔记基于 AUTOSAR Adaptive Platform 官方文档 R20-11 版本 AUTOSAR_EXP_PlatformDesign.pdf.作者:Zijian/TENG 原文地 ...

  6. Excel 快速跳转到工作表

    新建 vba 模块 Sub GotoSheet() tname = InputBox("input table name") If StrPtr(tname) = 0 Then E ...

  7. Hopper Disassembler系列之Sublime Text 3 爆破

    https://www.52pojie.cn/thread-793069-1-1.html 当参数少于7个时, 参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9. 当参数 ...

  8. Redis的安装、基本使用以及与SpringBoot的整合

    1.概述 Redis 是现在很流行的一个 NoSql 数据库,每秒读取可以达到10万次,能够将数据持久化,支持多种数据结构,容灾性强,易扩展,常用于项目的缓存中间件. 今天我们就来聊聊关于Redis的 ...

  9. Android系统编程入门系列之应用内数据保存数据库

    上篇文章已经介绍了如何使用SharedPreferences存储键值对形式的轻量级数据,对于那些相同结构的多组数据,类似于存储Java中定义的类的多个对象属性值,如果按照键值对的形式一条条读写,需要分 ...

  10. IKEv2协议关键知识点总结整理

    文章目录 @[toc] 1. IKEv2基本原理 2. IKEv2协议重点注意事项 2.1 情景一:==IKEv2协商密钥逻辑== ①密钥协商流程 ②函数调用关系 ③流程简述 2.2 情景二:==使用 ...