unity学习笔记#2--unity对象池

来源:互联网 发布:网页版淘宝的微淘 编辑:程序博客网 时间:2024/06/07 20:21

最近在看教程,学到了一点关于unity对象池的技术,现在来总结一下。

1.适用范围

在游戏中,总会有一些对象会重复出现在游戏场景中,比如敌人、子弹、特效……这些对象如果用一般的生成(Instantiate)及销毁(Destroy)方法来使其出现或消失在游戏场景中时,往往会造成很大的性能开销,尤其是在移动设备,如果大量使用此方法来处理对象的话会使得游戏变卡顿,影响游戏体验。因此可以用对象池技术来解决这个问题。

2.关于对象池

对象池就是将要重复出现在游戏场景中的物体(即可复用对象)在进入游戏场景中时预先生成,将其设置为未激活状态(设置SetActive属性为false,防止其在场景中出现)并存放在对象池中,当要让该物体出现在场景中时,将该物体从对象池中取出,激活并移动至指定地方。而当要让该物体消失于场景中时,则将其放入对象池中,并将其各项数值重置为默认(一些粒子对象是在播放完特效才消失的,便需要将其重置到播放前的状态),再设置其为未激活状态,需要注意的是,每个对象池里存储的可复用物体不能太多。

3.实现思路

以下为我参照教程中的方法整理的对象池实现思路图,可能有些简陋:
对象池实现思路
以及实现对象池时所用的脚本的功能图:
所用脚本的功能

4.代码

废话不多说,下面贴出所用脚本的代码:

using System.Collections;using System.Collections.Generic;using UnityEngine;//作为静态方法public class GameObjectUtil  {    private static Dictionary<RecycleGameObject,ObjectPool> pools=new Dictionary<RecycleGameObject, ObjectPool>();    //提供一个实例化方法    public static GameObject Instantiate(GameObject prefab, Vector3 pos)    {        GameObject instance;        RecycleGameObject reference = prefab.GetComponent<RecycleGameObject>();        //检查是否为可复用对象        if (reference!=null)        {            //取得该预制体的对象池             var pool= GetObjectPool(reference);            //在对象池中生成克隆体,得到该克隆体            instance = pool.NextObject(pos).gameObject;            return instance;        }        else        {            //调用monobehaviour自带的实例化方法直接生成克隆体            instance = GameObject.Instantiate(prefab);            instance.transform.position = pos;            return instance;        }    }    /// <summary>    /// 提供一个销毁方法    /// </summary>    /// <param name="prefab">待克隆的预制体</param>    public static void Destroy(GameObject prefab)    {        RecycleGameObject temp = prefab.GetComponent<RecycleGameObject>();        //检查是否为可复用对象        if (temp!=null)        {            temp.ShutDown();        }        else        {            Destroy(prefab);        }    }    /// <summary>    /// 获取对象的对象池    /// </summary>    /// <param name="reference"></param>    /// <returns></returns>    private static ObjectPool GetObjectPool(RecycleGameObject reference)    {        ObjectPool pool;        //查询字典里有没有该对象相对应的对象池        if (pools.ContainsKey(reference))        {            //得到相应的对象池            pool = pools[reference];            return pool;        }        else        {            //没有对象池的话新建一个对象池            var poolContainer=new GameObject(reference.gameObject.name+"pool");            //添加对象池管理组件            pool = poolContainer.AddComponent<ObjectPool>();            //将预制体绑定到对象池中            pool.prefab = reference;            //将预制体与对象池添加到字典中            pools.Add(reference,pool);            return pool;        }    }}

注:其中GameObjectUtil类为静态类,不需要继承monobehaviour类,也无需挂载到游戏对象中。

using System.Collections;using System.Collections.Generic;using UnityEngine;public class ObjectPool : MonoBehaviour {    //对象池的管理脚本    public  List<RecycleGameObject> poolInstance=new List<RecycleGameObject>();    public RecycleGameObject prefab;    /// <summary>    /// 创建预制体的克隆体    /// </summary>    /// <param name="pos">克隆体的位置</param>    /// <returns></returns>    private RecycleGameObject CreateObject(Vector3 pos)    {        //实例化克隆体        var clone=GameObject.Instantiate(prefab);        //设置克隆体的位置        clone.transform.position = pos;        //将克隆体作为对象池的子对象        clone.transform.parent = transform;        //将克隆体加入到列表中        poolInstance.Add(clone);        return clone;    }    /// <summary>    /// 取出克隆体    /// </summary>    /// <param name="pos">克隆体的位置</param>    /// <returns></returns>    public RecycleGameObject NextObject(Vector3 pos)    {        RecycleGameObject instance = null;        //调用方法获取克隆体实例        instance = CreateObject(pos);        //激活克隆体        instance.Restart();        return instance;    }}
using System.Collections;using System.Collections.Generic;using UnityEngine;public class RecycleGameObject : MonoBehaviour {    //通过设置游戏对象的SetActive属性来激活/关闭游戏对象,并作为判断此物体是否为可复用对象的标准    public void Restart()    {        gameObject.SetActive(true);    }    public void ShutDown()    {        gameObject.SetActive(false);    }}

5.使用方法

只需要在预制件里挂上RecycleGameObject脚本,就能将此物体作为可复用的物体。调用GameObjectUtil类里面的Instantiate方法就能实例化物体及其对象池。比如我要生成个对象池,里面有3个物体。那我可以这样写个脚本来调用。

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Test : MonoBehaviour{    public int mun;    public GameObject prefab;    private Vector3 pos;    // Use this for initialization    void Start ()    {        pos = transform.position+Vector3.right;    }    // Update is called once per frame    void Update () {        if (mun>0)        {            GameObjectUtil.Instantiate(prefab,pos);            mun--;        }    }}

在场景中放入一个Cube,挂载上此脚本,如图设置:
Test设置
为脚本中的prefab指定物体,在这里我指定了一个Sphere,Sphere里挂载了RecycleGameObject脚本,运行情况如图:
运行效果

克隆体
可以看到对象池里有3个对象,且对象池中的物体都挂载了RecycleGameObject脚本。

原创粉丝点击