游戏物体复用:对象池(以Unity3D为例)

 

需要解决/优化的问题:

在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()生命周期,必需的情况下可以手动

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值