需要解决/优化的问题:
在Unity3D中,实例化物体和销毁物体是都非常消耗性能的,小项目可能没问题的,但是一旦有大量的物体在短时间内需要销毁或者创建,那么游戏就会变得巨卡,如果是手游你的手机还会变烫,非常影响游戏体验,所以要尽量避免过多的使用Instantiate和Destroy操作
很容易想到,可以用物体隐藏和显示来代替物体的创建与销毁(也就是SetActive操作)而这也是对象池所做的事
核心代码:
脚本使用说明(该脚本名为Pool):
- Pool.Get(key, path, pos, rot, name):创建并返回一个GameObject,这个GameObject的路径是path(Resources文件下的路径),它出现在位置pos上,旋转角为rot,名字为name,使用的预制体名字为key,要保证在Resources文件夹中存在名字为key的预制体
- Pool.Return(name):销毁名字为name的GameObject
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pool : MonoBehaviour
{
public static Pool instance;
public static Dictionary<string, ArrayList> dic = new Dictionary<string, ArrayList>(); //创建一个字典dic,键为类名,值为对象数组
#region 单例模式
public static Pool GetPool
{
get
{
if (instance == null)
instance = new Pool();
return instance;
}
}
#endregion
/// <summary>
/// Get(预制体名字,预制体所在Resources的路径,初始位置,初始旋转角,是否是UI预制体,预制体改名,可缺省)
/// </summary>
public static GameObject Get(string key, string path, Vector3 position, Quaternion roration, string keyName = "")
{
GameObject need;
string name = key + "(Clone)";
if (keyName != "")
name = keyName;
if (dic.ContainsKey(name) && dic[name].Count > 0) //如果该对象在池中存在,复用该对象
{
ArrayList list = dic[name];
need = (GameObject)list[0];
list.RemoveAt(0);
need.SetActive(true);
need.transform.position = position;
need.transform.rotation = roration;
}
else
{
need = Instantiate(Resources.Load(path), position, roration) as GameObject; //不存在就直接创建
need.name = name;
}
return need;
}
public static GameObject Return(GameObject unNeed) //这个物体已经用不到了,丢入对象池
{
string key = unNeed.name;
if (dic.ContainsKey(key))
dic[key].Add(unNeed);
else
dic[key] = new ArrayList() { unNeed };
unNeed.SetActive(false); //可以理解为将物体丢入对象池就是隐藏该物体
return unNeed;
}
public static void ClearPool()
{
dic.Clear();
}
}
注意事项:
- 隐藏的物体在切换场景时会被系统自动回收/销毁!也就是说如果你在场景1中回收物体A,并在场景B中取出物体A,那么就会出现错误!所以如果想要在多场景中使用,需要将该脚本挂在物体上面,或者单例设计模式的话,每次切换场景时手动清空字典(Dictionary)里面的元素
- 用对象池的方法创建物体时,不会自动执行物体身上脚本中的Start()和Awake()生命周期,必需的情况下可以手动