对象池
顾名思义,对象池是存放对象的缓冲区。用户可以从缓冲区中放入/取出对象。一类对象池存放一类特定的对象。那么对象池有什么用呢?在游戏中,经常会有产生/销毁大量同类游戏对象的需求,比如游戏中源源不断的敌人、频繁刷新的宝箱、乃至一些游戏特效(风、雨等)。如果没有一种比较好的机制来管理这些对象的产生和销毁,而是一昧的Instantiate和Destroy,将使你的游戏性能大大下降,甚至出现卡死、崩溃…
简而言之,就是当需要使用一个对象的时候,直接从该类对象的对象池中取出(SetActive(true)),如果对象池中无可用对象,再进行Instantitate。而当不再需要该对象时,不直接进行Destroy,而是SetActive(false)并将其回收到对象池中。
搜,这个时候对象池该上场了
(1)简易版
这里我使用到的是字典键值对的方式进行存储、当然还有堆栈的方式。大家可以去其他博客进行参考
//==========================
// - FileName: PrefabTool.cs
// - Created: true.
// - CreateTime: 2020/02/27 22:49:01
// - Region: China WUHAN
// - Description:
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PrefabTool
{
//通过单例拿到对象池
private static PrefabTool _ins;
public static PrefabTool Getins()
{
if (_ins==null)
{
_ins = new PrefabTool();
}
return _ins;
}
/// <summary>
/// 1、加载预制件
/// 2、把加载完成的预制件放在对象池
/// 3、预制件不会删除,将预制件重用
///</summary>
//1、生成一个存储对象预制件的库,使用字典:键值对
Dictionary<string, GameObject> prefadic = new Dictionary<string, GameObject>();
//2、用一个泛型集合List存储所有的对象
Dictionary<string, List<GameObject>> objDic = new Dictionary<string, List<GameObject>>();
//加载预制件
public GameObject LoadPre(string Path)
{
//判断对象池中是否有对象
if (!prefadic.ContainsKey(Path))
{
//如果没有对象就把对象加载到池子中
GameObject preObj = Resources.Load<GameObject>(Path);
//通过地址添加预制体
prefadic.Add(Path, preObj);
}
//如果有的话就直接使用
GameObject obj = prefadic[Path];
//返回一个预制体对象
return obj;
}
//用来存储预制体对象
public GameObject GetInsObj(string Path)
{
//如果没有根据键查找到对象的话
if (!prefadic.ContainsKey(Path))
{
objDic.Add(Path, new List<GameObject>());
}
//将预制体的地址存到一个泛型集合中
List<GameObject> insit = objDic[Path];
//如果集合中没有元素
if (insit.Count == 0)
{
//加载
GameObject preobjObj = LoadPre(Path);
insit.Add(GameObject.Instantiate<GameObject>(preobjObj));
}
GameObject game = insit[insit.Count - 1];
//删除集合中的最后一个
insit.Remove(game);
//返回游戏对象
return game;
}
//回收游戏对象
public void Remove(string Path,GameObject obj)
{
if (objDic.ContainsKey(Path))
{
objDic[Path].Add(obj);
}
else
{
Debug.Log("键值错误.....");
}
}
}
另外就是通过一个路径(静态类、使用const常量进行修饰)来进行存储:
//==========================
// - FileName: PrefabConst.cs
// - Created: true.
// - CreateTime: 2020/02/27 22:48:01
// -
// - Region: China WUHAN
// - Description:
//==========================
public static class PrefabConst
{
//预制件路径
public const string bullet = "**";
}
(2)使用堆栈就行制作对象池、升级版
//==========================
// - FileName: ObjectPool.cs
// - Created: true.
// - CreateTime: 2020/04/21 22:25:45
// - Email:
// - Region: China WUHAN
// - Description:
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectPool : MonoBehaviour
{
//游戏物体对象池
public Stack<GameObject> PoolStack;
//激活游戏物体的列表
public Stack<GameObject> ActiveList;
public ObjectPool()
{
PoolStack = new Stack<GameObject>();
ActiveList = new Stack<GameObject>();
}
private static ObjectPool _instance;
public static ObjectPool Instance
{
get
{
if (_instance == null)
{
_instance = new ObjectPool();
}
return _instance;
}
}
//取得游戏物体
public GameObject GetObj(string Path,Transform Parent)
{
GameObject Go = null;
//是否有游戏物体
if (PoolStack.Count <= 0)
{
//生成物体
Go = Instantiate(Resources.Load("Prefabs/" + Path) as GameObject);
Go.transform.position = Vector3.one;
Go.transform.SetParent(Parent);
}
else
{
//弹出栈
Go = PoolStack.Pop();
//激活
Go.SetActive(true);
Go.transform.SetParent(Parent);
}
return Go;
}
//压栈、放回对象池
public void PushMonster(GameObject Prefab)
{
//禁用游戏物体
Prefab.SetActive(false);
//压栈
PoolStack.Push(Prefab);
}
}
Demo:
//==========================
// - FileName: ObjectTest.cs
// - Created: true.
// - CreateTime: 2020/04/21 22:29:20
// - Region: China WUHAN
// - Description:
//==========================
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectTest : MonoBehaviour
{
public Transform Parent;
private ObjectPool objectPool;
public bool isPlay = true;
private void Start()
{
objectPool = ObjectPool.Instance;
ObjectPool.Instance.GetObj("Plane", Parent);
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.A))
{
isPlay = true;
//从池子中取得游戏物体
GameObject go = objectPool.GetObj("Chump", Parent);
go.transform.position = Vector3.one;
//讲拿到的物体放到怪物列表中
objectPool.ActiveList.Push(go);
}
else if (Input.GetKeyDown(KeyCode.D))
{
if (!isPlay)
{
return;
}
//判断激活列表是否有元素
if (objectPool.ActiveList.Count >= 0)
{
objectPool.PushMonster(objectPool.ActiveList.Pop());
}
}
else if (objectPool.ActiveList.Count == 0)
{
isPlay = false;
}
}
}