Unity3D中对象池的使用

来源:互联网 发布:java插件下载 编辑:程序博客网 时间:2024/05/18 16:56

Unity3D中对象池的使用


原文地址:点击
翻译:claudio 



The script is really simple but it has helped the performance in my iOS game tremendously by limiting the number of instantiations that happen at runtime.

这个脚本非常简单,但它可以通过大量减少实例化所带来的开销使我的iOS游戏得到很大的性能提升。

What it does:

The object pool allow you to buffer or pool objects you plan on reusing many time throughout your game, by allowing you to request a new object from it, and tell it whether or not it must give you an object or only give you an object thats available. It also buffers objects at the start to give you a pool to work with initially.

对象池可以缓存你计划在游戏中重复利用的对象,并允许你从中调用,同时它也可以判断是否响应你的调用或者只给你提供可用的对象。它也可以在一开始缓存很多对象来为你提供一个池来进行工作。

How to use:

  1. Add the ObjectPool.cs behavior to a GameObject.
  2. In the object prefabs array set the prefabs you want to be pooled and reused throughout the game.
  3. In the amount to buffer array, specify how many of each object you want to instantiate on the scene start so you have pooled objects to start with. If you don't want to specify each, the default buffer amount will just be used.
  4. In your game call ObjectPool.instance.GetObjectForType(objectType,onlyPooled). For the object type just give the name of the prefab you want to spawn. Specify true or false for the onlyPooled value, if true it will only return a GameObject if there is already an object pooled, if false it will instantiate a new object if one is not available. (Set true if you want to limit how many objects are pooled, very helpful if you want a limited number of effects to ever happen at one time).
  5. Make sure your Gameobject you get from the pool knows when to add itself back into the pool if removed.
  1. 把脚本ObjectPool.cs链接到一个GameObject上。
  2. 在物体预设数组中设置你想要放到池中并重复利用的预设物体。
  3. 在缓冲数组中,指定你希望每个物体在游戏开始时被实例化的数量,这样在开始的时候你就有了池对象。
  4. 在你的游戏中调用ObjectPool.instance.GetObjectForType(objectType,onlyPooled)来使用它。objectType写你想生成的预设的名字、并为onlyPooled指定布尔值,如果返回真,它将返回你已经放到池中的对象;如果返回假,它将实例化一个全新的对象。(如果你想限制被池对象的数量,那么设定为真,这样做非常有用,尤其是在需要限制同时播放特效的数量的时候)。
  5. 确保你从池中调用的对象知道当它被删除时需要返回到池中。

I have also included the Effect.cs and SoundEffect.cs I use in my game to get anyone started right away. The Effect.cs behavior should be added to a game object, then have any number of ParticleEmitters added to it which will run a single emit each time StartEffect is called. Then after a set amount of time it will reset the effect and pool itself. SoundEffect, does a similar thing but with sound effects.

我同时写了Effect.cs和SoundEffect.cs脚本,并把他们用到了游戏中所有需要的地方。Effect.cs脚本需要链接到一个game object上,之后需要加入一些粒子发射器到脚本,当StartEffect被调用时,每次只运行一次发射。然后在过了设定的时间后,它将重置特效并把自己放回池中。SoundEffect的功能和它差不多,只是利用在音效上。

I hope this can help people out who need to limit the number of instantiate calls made with reusable objects.

我希望这个可以帮到有需要的人。

ObjectPool.cs

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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
**Code (csharp):**   
 
usingUnityEngine;
usingSystem.Collections;
usingSystem.Collections.Generic;
 
publicclass ObjectPool : MonoBehaviour
{
 
    publicstatic ObjectPool instance;
 
    /// <summary>
    /// The object prefabs which the pool can handle.
    /// </summary>
    publicGameObject[] objectPrefabs;
 
    /// <summary>
    /// The pooled objects currently available.
    /// </summary>
    publicList<GameObject>[] pooledObjects;
 
    /// <summary>
    /// The amount of objects of each type to buffer.
    /// </summary>
    publicint[] amountToBuffer;
 
    publicint defaultBufferAmount = 3;
 
    /// <summary>
    /// The container object that we will keep unused pooled objects so we dont clog up the editor with objects.
    /// </summary>
    protectedGameObject containerObject;
 
    voidAwake ()
    {
        instance = this;
    }
 
    // Use this for initialization
    voidStart ()
    {
        containerObject = newGameObject("ObjectPool");
 
        //Loop through the object prefabs and make a new list for each one.
        //We do this because the pool can only support prefabs set to it in the editor,
        //so we can assume the lists of pooled objects are in the same order as object prefabs in the array
        pooledObjects = newList<GameObject>[objectPrefabs.Length];
 
        inti = 0;
        foreach( GameObject objectPrefab inobjectPrefabs )
        {
            pooledObjects[i] = newList<GameObject>();
 
            intbufferAmount;
 
            if(i < amountToBuffer.Length) bufferAmount = amountToBuffer[i];
            else
                bufferAmount = defaultBufferAmount;
 
            for( intn=0; n<bufferAmount; n++)
            {
                GameObject newObj = Instantiate(objectPrefab) asGameObject;
                newObj.name = objectPrefab.name;
                PoolObject(newObj);
            }
 
            i++;
        }
    }
 
    /// <summary>
    /// Gets a new object for the name type provided.  If no object type exists or if onlypooled is true and there is no objects of that type in the pool
    /// then null will be returned.
    /// </summary>
    /// <returns>
    /// The object for type.
    /// </returns>
    /// <param name='objectType'>
    /// Object type.
    /// </param>
    /// <param name='onlyPooled'>
    /// If true, it will only return an object if there is one currently pooled.
    /// </param>
    publicGameObject GetObjectForType ( stringobjectType , boolonlyPooled )
    {
        for(inti=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;
                    pooledObject.SetActiveRecursively(true);
 
                    returnpooledObject;
 
                }elseif(!onlyPooled) {
                    returnInstantiate(objectPrefabs[i]) asGameObject;
                }
 
                break;
 
            }
        }
 
        //If we have gotten here either there was no object of the specified type or non were left in the pool with onlyPooled set to true
        returnnull;
    }
 
    /// <summary>
    /// Pools the object specified.  Will not be pooled if there is no prefab of that type.
    /// </summary>
    /// <param name='obj'>
    /// Object to be pooled.
    /// </param>
    publicvoid PoolObject ( GameObject obj )
    {
        for( inti=0; i<objectPrefabs.Length; i++)
        {
            if(objectPrefabs[i].name == obj.name)
            {
                obj.SetActiveRecursively(false);
                obj.transform.parent = containerObject.transform;
                pooledObjects[i].Add(obj);
                return;
            }
        }
    }
 
}

Effect.cs

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
**Code (csharp):**  
 
usingUnityEngine;
usingSystem.Collections;
 
publicclass Effect : MonoBehaviour
{
    /// <summary>
    /// The array of emitters to fire when the effect starts.
    /// </summary>
    publicParticleEmitter[] emitters;
 
    /// <summary>
    /// The length of the effect in seconds.  After which the effect will be reset and pooled if needed.
    /// </summary>
    publicfloat effectLength = 1f;
 
 
    /// <summary>
    /// Should the effect be added to the effects pool after completion.
    /// </summary>
    publicbool poolAfterComplete = true;
 
 
 
    /// <summary>
    /// Resets the effect.
    /// </summary>
    publicvirtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        }else{
            Destroy(gameObject);
        }
    }
 
    /// <summary>
    /// Starts the effect.
    /// </summary>
    publicvirtual void StartEffect ()
    {
        foreach( ParticleEmitter emitter inemitters )
        {
            emitter.Emit();
        }
 
        StartCoroutine(WaitForCompletion());
    }
 
    publicIEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yieldreturn new WaitForSeconds(effectLength);
 
        //Reset the now completed effect
        ResetEffect();
 
    }
 
}

SoundEffect.cs

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
usingUnityEngine;
usingSystem.Collections;
 
publicclass SoundEffect : MonoBehaviour
{
 
    /// <summary>
    /// The sound source that will be played when the effect is started.
    /// </summary>
    publicAudioSource soundSource;
 
    /// <summary>
    /// The sound clips that will randomly be played if there is more than 1.
    /// </summary>
    publicAudioClip[] soundClips;
 
    /// <summary>
    /// The length of the effectin seconds.
    /// </summary>
    publicfloat effectLength = 1f;
 
    /// <summary>
    /// Should the effect be pooled after its completed.
    /// </summary>
    publicbool poolAfterComplete = true;
 
 
 
    /// <summary>
    /// Resets the effect.
    /// </summary>
    publicvirtual void ResetEffect ()
    {
        if(poolAfterComplete)
        {
            ObjectPool.instance.PoolObject(gameObject);
        }else{
            Destroy(gameObject);
        }
    }
 
    /// <summary>
    /// Starts the effect.
    /// </summary>
    publicvirtual void StartEffect ()
    {
        soundSource.PlayOneShot(soundClips[Random.Range(0,soundClips.Length)]);
 
        StartCoroutine(WaitForCompletion());
    }
 
    publicIEnumerator WaitForCompletion ()
    {
        //Wait for the effect to complete itself
        yieldreturn new WaitForSeconds(effectLength);
 
        //Reset the now completed effect
        ResetEffect();
 
    }
}
0 0
原创粉丝点击