192 lines
7.4 KiB
C#
192 lines
7.4 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace Microsoft.MixedReality.Toolkit.Utilities.GameObjectManagement
|
|
{
|
|
/// <summary>
|
|
/// Used to recycle Unity GameObjects. When ever you create GameObjects during runtime some overhead is incurred. Additionally
|
|
/// memory can become highly fragment as well as possibly causing the garbage collector to perform a collection (which is also
|
|
/// a performance hit). This is especially prevalent when you are spawning and destroying GameObjects of the same type
|
|
/// very quickly in large quantities (such as bullets). The GameObject pool allows you to recycle objects so they can be
|
|
/// reused upon request.
|
|
/// </summary>
|
|
/// <example>
|
|
/// Setup code for using the generic prefab instance creator:
|
|
/// <code>
|
|
/// GameObjectPool pool = new GameObjectPool();
|
|
/// GenericPrefabInstanceCreator creator = new GenericPrefabInstanceCreator();
|
|
/// creator.Prefab = MyProjectilePrefab;
|
|
/// pool.AddCreator(creator, "projectile1");
|
|
/// </code>
|
|
/// Requesting a game object from the pool:
|
|
/// <code>
|
|
/// var myProjectileObj = pool.GetGameObject("projectile1");
|
|
/// </code>
|
|
/// Recycling the game object:
|
|
/// <code>
|
|
/// pool.Recycle(myProjectileObj, "projectile1");
|
|
/// </code>
|
|
/// </example>
|
|
/// <remarks>Note that the GameObjectPool is not thread safe. It should only be used in Unity's main thread.</remarks>
|
|
public class GameObjectPool
|
|
{
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="GameObjectPool"/> class.
|
|
/// </summary>
|
|
public GameObjectPool()
|
|
{
|
|
_pool = new Dictionary<string, Queue<GameObject>>();
|
|
_creators = new Dictionary<string, GameObjectCreator>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// GameObjects are created by an implementation of IGameObjectCreator in this GameObjectPool. This
|
|
/// method adds your implementation of the IGameObjectCreator to use for objects that share a specific
|
|
/// object identifier.
|
|
/// </summary>
|
|
/// <param name="creator">The implementation of IGameObjectCreator to use for GameObjects associated with the objectIdentifier.</param>
|
|
/// <param name="objectIdentifier">The identifier you want to use to identify the kind of game objects you want to create.</param>
|
|
public void AddCreator(GameObjectCreator creator, string objectIdentifier)
|
|
{
|
|
_creators.Add(objectIdentifier, creator);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a game object under a specific object identifier to the GameObjectPool.
|
|
/// </summary>
|
|
/// <param name="gameObject">The GameObject to recycle.</param>
|
|
/// <param name="objectIdentifier">The identifier you want to use to identify the kind of game object you are recycling.</param>
|
|
public void Recycle(GameObject gameObject, string objectIdentifier)
|
|
{
|
|
EnsureListForObjectID(objectIdentifier);
|
|
|
|
if (_creators.ContainsKey(objectIdentifier))
|
|
{
|
|
_creators[objectIdentifier].PrepareForRecycle(gameObject);
|
|
}
|
|
|
|
gameObject.SetActive(false);
|
|
_pool[objectIdentifier].Enqueue(gameObject);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a game object for a specific object identifier from the GameObjectPool. If the kind of game object
|
|
/// being requested is not in the pool, then it will get created by a IGameObjectCreator that was
|
|
/// added to the pool for handling objects associated with the objectIdentifier.
|
|
/// </summary>
|
|
/// <param name="objectIdentifier">The identifier you want to use to identify the kind of game object you want to retrieve.</param>
|
|
/// <param name="position">The position that the game object should have before it is activated.</param>
|
|
/// <param name="rotation">The rotation that the game object should have before it is activated.</param>
|
|
public GameObject GetGameObject(string objectIdentifier, Vector3 position, Quaternion rotation)
|
|
{
|
|
GameObject obj = null;
|
|
GameObjectCreator creator = null;
|
|
if (_creators.ContainsKey(objectIdentifier))
|
|
{
|
|
creator = _creators[objectIdentifier];
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("Unable to create a GameObject for object ID '" + objectIdentifier + "' because no IGameObjectCreator implementation can be found for it.");
|
|
return null;
|
|
}
|
|
|
|
EnsureListForObjectID(objectIdentifier);
|
|
|
|
Queue<GameObject> objects = _pool[objectIdentifier];
|
|
|
|
if (objects.Count > 0)
|
|
{
|
|
obj = objects.Dequeue();
|
|
}
|
|
else
|
|
{
|
|
obj = creator.Instantiate();
|
|
}
|
|
|
|
if (obj != null)
|
|
{
|
|
creator.PrepareForUse(obj);
|
|
obj.SetActive(true);
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Same as calling GetGameObject(objectIdentifier, Vector3.zero, Quaternion.identity)
|
|
/// </summary>
|
|
/// <param name="objectIdentifier">The identifier you want to use to identify the kind of game object you want to retrieve.</param>
|
|
public GameObject GetGameObject(string objectIdentifier)
|
|
{
|
|
return GetGameObject(objectIdentifier, Vector3.zero, Quaternion.identity);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the number of game objects in the pool for a specific identifier.
|
|
/// </summary>
|
|
public int Count(string objectIdentifier)
|
|
{
|
|
EnsureListForObjectID(objectIdentifier);
|
|
|
|
return _pool[objectIdentifier].Count;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and destroys all game objects in the pool associated with the specified objectIdentifier.
|
|
/// </summary>
|
|
/// <param name="objectIdentifier">The identifier you want to use to identify the kind of game objects to remove from the pool.</param>
|
|
public void EmptyPool(string objectIdentifier)
|
|
{
|
|
EnsureListForObjectID(objectIdentifier);
|
|
|
|
Queue<GameObject> objects = _pool[objectIdentifier];
|
|
foreach (GameObject obj in objects)
|
|
{
|
|
GameObject.Destroy(obj);
|
|
}
|
|
objects.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes and destroys all game objects in the pool.
|
|
/// </summary>
|
|
public void EmptyPool()
|
|
{
|
|
foreach (string objectID in _pool.Keys)
|
|
{
|
|
EmptyPool(objectID);
|
|
}
|
|
_pool.Clear();
|
|
}
|
|
|
|
#region Private
|
|
|
|
/// <summary>
|
|
/// The pool for game objects
|
|
/// </summary>
|
|
private Dictionary<string, Queue<GameObject>> _pool;
|
|
|
|
/// <summary>
|
|
/// All creators that this pool can handle by identifier
|
|
/// </summary>
|
|
private Dictionary<string, GameObjectCreator> _creators;
|
|
|
|
/// <summary>
|
|
/// Ensures there is a list for the specified identifier
|
|
/// </summary>
|
|
private void EnsureListForObjectID(string objectIdentifier)
|
|
{
|
|
if (!_pool.ContainsKey(objectIdentifier))
|
|
{
|
|
_pool.Add(objectIdentifier, new Queue<GameObject>());
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|