目录
前言
仅个人学习的记录,旨在分享我的学习笔记和个人见解。
一、对象池简介
Unity对象池是一种用于管理和重复使用游戏对象的技术。它可以减少在游戏中频繁创建和销毁游戏对象,从而减少内存占用和提高游戏性能。通过对象池,游戏对象可以被预先创建并缓存在内存中,当需要时可以从池中获取并激活,使用完毕后则放回对象池以便下次重复利用。
二、实现步骤
1.新建脚本ObjectPool.cs
使用单例模式,通过字典的方式存储各个对象的队列。
代码如下
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool
{
private static ObjectPool instance; // 单例
private GameObject pool;// 对象池游戏物体
private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();// 对象池字典,(string对象名字,对象队列)
public static ObjectPool Instance
{
get
{
if (instance == null)
{
instance = new ObjectPool();
}
return instance;
}
}
}
2.添加 获取对象 方法
先判断字典中是否包含对象队列 或 对象队列中是否有可用对象。
若队列中没有可用的对象,先实例化一个对象加入对应池子中,再从对应池子中获取对象。
为了后续便于管理,在实例化对象时,会自动在pool对象下建立 “对象名Pool”(如 子弹Pool),并在“对象名Pool”下存放被实例化的对象。
具体方法如下:
public GameObject GetObject(GameObject prefab)
{
GameObject _object;
//若场景中没有ObjectPool物体,则新生成一个物体 并 新建字典。
pool = GameObject.Find("ObjectPool");
if (!pool)
{
pool = new GameObject("ObjectPool");
objectPool = new Dictionary<string, Queue<GameObject>>();
}
//如果对应池子里没有该可用对象
if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0)
{
_object = GameObject.Instantiate(prefab);//实例化对象,加入队列
PushObject(_object);//回收对象到对应池子,并设置为隐藏
//查找ObjectPool下是否有对饮 名字的池子物体
GameObject childPool = GameObject.Find("ObjectPool/"+prefab.name + "Pool");
if (!childPool)
{
childPool = new GameObject(prefab.name + "Pool");
childPool.transform.SetParent(pool.transform);
}
_object.transform.SetParent(childPool.transform);//存放到对应池子物体位置下
}
_object = objectPool[prefab.name].Dequeue();//对应池子中的对象出列。
_object.SetActive(true);
return _object;
}
3.添加 回收对象 方法
先判断字典中是否有对象名的key,若没有则新建一条数据加入字典中。再把要回收的对象加入字典里对应key值的队列中。
具体方法如下:
public void PushObject(GameObject prefab)
{
string _name = prefab.name.Replace("(Clone)", string.Empty);
//如果字典中没有对应的key值,则新建一条数据
if (!objectPool.ContainsKey(_name))
objectPool.Add(_name, new Queue<GameObject>());
//对象入列
objectPool[_name].Enqueue(prefab);
prefab.SetActive(false);
}
到这里,一个简单的对象池就已经搭建完成啦。
4.完整代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool
{
private static ObjectPool instance; // 单例
private GameObject pool;// 对象池游戏物体
private Dictionary<string, Queue<GameObject>> objectPool = new Dictionary<string, Queue<GameObject>>();// 对象池字典,(string对象名字,对象队列)
public static ObjectPool Instance
{
get
{
if (instance == null)
{
instance = new ObjectPool();
}
return instance;
}
}
public GameObject GetObject(GameObject prefab)
{
GameObject _object;
//若场景中没有ObjectPool物体,则新生成一个物体 并 新建字典。
pool = GameObject.Find("ObjectPool");
if (!pool)
{
pool = new GameObject("ObjectPool");
objectPool = new Dictionary<string, Queue<GameObject>>();
}
//如果对应池子里没有该可用对象
if (!objectPool.ContainsKey(prefab.name) || objectPool[prefab.name].Count == 0)
{
_object = GameObject.Instantiate(prefab);//实例化对象,加入队列
PushObject(_object);//存储对象到对应池子,并设置为隐藏
//查找ObjectPool下是否有对饮 名字的池子物体
GameObject childPool = GameObject.Find("ObjectPool/"+prefab.name + "Pool");
if (!childPool)
{
childPool = new GameObject(prefab.name + "Pool");
childPool.transform.SetParent(pool.transform);
}
_object.transform.SetParent(childPool.transform);//存放到对应池子物体位置下
}
_object = objectPool[prefab.name].Dequeue();//对应池子中的对象出列。
_object.SetActive(true);
return _object;
}
public void PushObject(GameObject prefab)
{
string _name = prefab.name.Replace("(Clone)", string.Empty);
//如果字典中没有对应的key值,则新建一条数据
if (!objectPool.ContainsKey(_name))
objectPool.Add(_name, new Queue<GameObject>());
//对象入列
objectPool[_name].Enqueue(prefab);
prefab.SetActive(false);
}
}
三、使用方法
例如,我想要生成“子弹”,只需要调用对象池的生成对象方法(GetObject),想要关闭“子弹”,则调用回收对象的方法(PushObject)
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class Test : MonoBehaviour
{
public GameObject bullet;//子弹预制体
void Update()
{
//按下鼠标左键生成子弹
if (Input.GetMouseButtonDown(0))
{
GameObject _bullet = ObjectPool.Instance.GetObject(bullet);
//延迟2秒后回收子弹到对象池中
float f = 0;
DOTween.To(() => f, a => f = a, 1f, 2f).OnComplete(() =>
{
ObjectPool.Instance.PushObject(_bullet);
});
}
}
}
四、效果展示
最后
文章内容仅为个人学习记录。好记性不如烂笔头,为了能更好的回顾和总结,开始记录与分享自己学到的Unity知识。若文章内容错误,麻烦指点。