《Unity3D》通过对象池模式,管理场景中的元素


原文链接:http://www.cnblogs.com/kimmy/p/3808007.html

池管理类有啥用?

在游戏场景中,我们有时候会需要复用一些游戏物体,比如常见的子弹、子弹碰撞类,某些情况下,怪物也可以使用池管理,UI部分比如:血条、文字等等

这些元素共同的特性是:存在固定生命周期,使用比较频繁,场景中大量使用。

所以,我们就通过池管理思路,在游戏初始化的时候,生成一个初始的池,存放我们要复用的元素,

当要用到时,从池中取出;生命周期结束,放回到池中。

代码

这个池的参数有两个:1池中存放的元素 2 池的初始容量(如果池不够了,则会按照这个容量进行扩展)

代码如下

复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 通用的池管理类
/// </summary>
public class ObjectPoolManager : MonoBehaviour
{
    #region 公共属性

    /// <summary>
    /// 池中所使用的元素Prefab
    /// </summary>
    public GameObject ObjPrefab;

    /// <summary>
    /// 初始容量
    /// </summary>
    public int InitialCapacity;

    #endregion

    #region 私有属性

    /// <summary>
    /// 初始下标
    /// </summary>
    private int _startCapacityIndex;

    /// <summary>
    /// 可用下标
    /// </summary>
    private List<int> _avaliableIndex;

    /// <summary>
    /// 池中全部元素
    /// </summary>
    private Dictionary<int, GameObject> _totalObjList;

    #endregion

    #region 事件/重写方法

    void Start()
    {
        _avaliableIndex = new List<int>(InitialCapacity);
        _totalObjList = new Dictionary<int, GameObject>(InitialCapacity);
        expandPool();
    }
    #endregion

    #region 公共方法

    /// <summary>
    /// 取得一个物体,返回值 1,obj代表,ID是1的物体被取到,ID可以用来归还物体的时候用到
    /// </summary>
    /// <returns></returns>
    public KeyValuePair<int, GameObject> PickObj()
    {

        if (_avaliableIndex.Count == 0)
            expandPool();

        int id = _avaliableIndex[0];
        _avaliableIndex.Remove(id);

        _totalObjList[id].SetActive(true);
        return new KeyValuePair<int, GameObject>(id, _totalObjList[id]);
    }

    /// <summary>
    /// 从池中取出元素,在制定时间后回收
    /// </summary>
    /// <param name="existSecond"></param>
    /// <returns></returns>
    public KeyValuePair<int, GameObject> PickObjWithDelayRecyle(float existSecond)
    {
        KeyValuePair<int, GameObject> obj = PickObj();
        StartCoroutine(startRecycleExplosion(obj.Key, existSecond));
        return obj;
    }


    /// <summary>
    /// 回收一个物体
    /// </summary>
    /// <param name="id"></param>
    public void RecyleObj(int id)
    {
        _totalObjList[id].SetActive(false);
        _totalObjList[id].transform.parent = transform;
        _avaliableIndex.Add(id);
    }

    #endregion

    #region 私有方法

    IEnumerator startRecycleExplosion(int id, float waitTime)
    {
        yield return new WaitForSeconds(waitTime);
        RecyleObj(id);
    }

    /// <summary>
    /// 扩展池
    /// </summary>
    private void expandPool()
    {
        int start = _startCapacityIndex;
        int end = _startCapacityIndex + InitialCapacity;

        for (int i = start; i < end; i++)
        {
            //加入验证判断,避免在多个请求同时触发扩展池需求
            if (_totalObjList.ContainsKey(i))
                continue;

            GameObject newObj = Instantiate(ObjPrefab) as GameObject;
            newObj.SetActive(false);
            _avaliableIndex.Add(i);
            _totalObjList.Add(i, newObj);
        }
        _startCapacityIndex = end;
    }
    #endregion
}
复制代码

 

值得注意的是:放回池中的时候,我们把元素的父节点也设置为池元素,这样做是避免当元素挂载的对象在内存中被删除的时候,元素也被删除的问题。

调用

 将本类挂载到场景中的某个GameObject上,在U3D编辑界面进行参数的赋值,就可以再游戏中访问了。

声明方式:

 ObjectPoolManager _bulletPool = GameObject.Find("你挂载的物体名称").GetComponent<ObjectPoolManager>();

取出元素:

  KeyValuePair<int, GameObject> bulletKV = _bulletPool.PickObj();

放回:

 _bulletPool.RecyleObj(bulletID);

 

在本人的实际使用中,用这个类管理了

  1. 子弹
  2. 子弹碰撞特效
  3. 攻击特效
  4. 被攻击特效
  5. 怪物血条(基于NGUI制作)
  6. 场景部分文字(施法时、怪物被攻击时,基于NGUI制作)
  7. 等等。。

欢迎各位进行讨论






[脚本]Unity 对象池创建, ObjectPool


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
   
/// <summary>
///  This is a class for Create Object pool in unity
///  to enhance game object instantiate and destroying performance
/// </summary>
public class ObjectPool : MonoBehaviour
{
   
     /// <summary>
     /// Object pool singleton
     /// </summary>
     public static ObjectPool instance;
     // Prefabs wants to be buffered or pooled
     public GameObject[] objectPrefabs;
     // List that holds each group pooled prefabs instances
     public List<GameObject>[] pooledObjects;
     // Aim to buffered or pooled counts for each prefabs
     public int [] amountToBuffer;
     // Default buffered or pooled counts for each prefab
     public int defaultBufferAmount = 3;
     // Empty game object that holds the object pool
     protected GameObject containerObject;
   
     /// <summary>
     /// Mono behaviour methods
     /// </summary>
     void Awake()
     {
         //  Sigleton assignment
         instance = this ;
     }
   
     void Start()
     {
         //  Initialize the object pool by Inspector setting
         containerObject = new GameObject( "ObjectPool" );
         pooledObjects = new List<GameObject>[objectPrefabs.Length];
         int i = 0;
         foreach (GameObject objectPrefab in objectPrefabs)
         {
             pooledObjects[i] = new List<GameObject>();
             int bufferAmount;
             if (i < amountToBuffer.Length)
                 bufferAmount = amountToBuffer[i];
             else
                 bufferAmount = defaultBufferAmount;
             for ( int n = 0; n < bufferAmount; n++)
             {
                 GameObject newObj = Instantiate(objectPrefab) as GameObject;
                 newObj.name = objectPrefab.name;
                 //  Init list the holds each prefabs pooled instance
                 PoolObject(newObj);
             }
             i++;
         }
     }
   
     /// <summary>
     /// Get pooled object by name from pool or instantiate a new one
     /// </summary>
     /// <param name="objectType"></param>
     /// <param name="onlyPooled"></param>
     /// <returns></returns>
     public GameObject GetObjectForType( string objectType, bool onlyPooled)
     {
         for ( int i = 0; i < objectPrefabs.Length; i++)
         {
             GameObject prefab = objectPrefabs[i];
             if (prefab.name == objectType)
             {
                 if (pooledObjects[i].Count > 0)
                 {
                     GameObject pooledObject = pooledObjects[i][0];
                     pooledObjects[i].RemoveAt(0);
                     pooledObject.transform.parent = null ;
#if UNITY_3_5
                     pooledObject.SetActiveRecursively ( true );
#elif UNITY_4_2
                     pooledObject.SetActive( true );
#endif
                     return pooledObject;
                 }
                 else if (!onlyPooled)
                 {
                     return Instantiate(objectPrefabs[i]) as GameObject;
                 }
                 break ;
             }
         }
         return null ;
     }
   
     /// <summary>
     /// Add object to pooled objects list
     /// </summary>
     /// <param name="obj"></param>
     public void PoolObject(GameObject obj)
     {
         for ( int i = 0; i < objectPrefabs.Length; i++)
         {
             if (objectPrefabs[i].name == obj.name)
             {
#if UNITY_3_5
                 obj.SetActiveRecursively ( false );
#elif UNITY_4_2
                 obj.SetActive( false );
#endif
                 obj.transform.parent = containerObject.transform;
                 pooledObjects[i].Add(obj);
                 return ;
             }
         }
     }
   
}

在Inspector随便设置一个prefab运行后,

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值