ObjectPool.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. namespace HQFPSWeapons
  4. {
  5. public class ObjectPool
  6. {
  7. public string Id { get => m_Id; }
  8. private GameObject m_Template;
  9. private Transform m_Parent;
  10. private string m_Id;
  11. private List<PoolableObject> m_AvailableObjects;
  12. private List<PoolableObject> m_InUseObjects;
  13. private int m_MinSize;
  14. private int m_MaxSize;
  15. private int m_CurrentSize;
  16. private bool m_Initialized;
  17. private float m_LastObjectGetTime;
  18. private bool m_AutoShrink;
  19. private float m_NextShrinkTime;
  20. private float m_AutoReleaseDelay;
  21. public ObjectPool(string id, GameObject template, int minSize, int maxSize, bool autoShrink, float autoReleaseDelay, Transform parent)
  22. {
  23. if(template == null)
  24. {
  25. Debug.LogError("You want to create an object pool for an object that is null!!");
  26. return;
  27. }
  28. // Create and store a new template, and it's hash code
  29. m_Template = Object.Instantiate(template, parent);
  30. m_Template.SetActive(false);
  31. m_Parent = parent;
  32. m_Id = id;
  33. // Store the min & max sizes for this pool
  34. m_MinSize = minSize;
  35. m_MaxSize = Mathf.Clamp(maxSize, m_MinSize, int.MaxValue);
  36. m_CurrentSize = m_MinSize;
  37. // Initialize the lists
  38. m_AvailableObjects = new List<PoolableObject>(m_MaxSize);
  39. m_InUseObjects = new List<PoolableObject>(m_MaxSize);
  40. // Spawn the default objects (more will be spawned if needed, according to minSize & maxSize)
  41. for(int i = 0;i < m_CurrentSize;i++)
  42. {
  43. PoolableObject obj = CreateNewObject(m_Template, m_Parent, m_Id);
  44. obj.gameObject.SetActive(false);
  45. m_AvailableObjects.Add(obj);
  46. }
  47. m_AutoShrink = autoShrink;
  48. m_AutoReleaseDelay = autoReleaseDelay;
  49. // Mark this pool as initialized. Means it can now be used.
  50. m_Initialized = true;
  51. }
  52. public void Update()
  53. {
  54. if(m_AutoShrink && m_AvailableObjects.Count > m_MinSize && Time.time > m_LastObjectGetTime + 60f && Time.time > m_NextShrinkTime)
  55. {
  56. PoolableObject objToDestroy = m_AvailableObjects[m_AvailableObjects.Count - 1];
  57. m_AvailableObjects.RemoveAt(m_AvailableObjects.Count - 1);
  58. Object.Destroy(objToDestroy);
  59. m_NextShrinkTime = Time.time + 0.5f;
  60. m_CurrentSize--;
  61. }
  62. }
  63. public PoolableObject GetObject()
  64. {
  65. if(!m_Initialized)
  66. {
  67. Debug.LogError("This pool can not be used, it's not initialized properly!");
  68. return null;
  69. }
  70. PoolableObject obj = null;
  71. if(m_AvailableObjects.Count > 0)
  72. {
  73. obj = m_AvailableObjects[m_AvailableObjects.Count - 1];
  74. // Move the object into the "in use list".
  75. m_AvailableObjects.RemoveAt(m_AvailableObjects.Count - 1);
  76. m_InUseObjects.Add(obj);
  77. }
  78. // Grow the pool.
  79. else if(m_CurrentSize < m_MaxSize)
  80. {
  81. m_CurrentSize++;
  82. obj = CreateNewObject(m_Template, m_Parent, m_Id);
  83. m_InUseObjects.Add(obj);
  84. }
  85. // The pool has reached it's max size, use the oldest in-use object.
  86. else
  87. {
  88. obj = m_InUseObjects[0];
  89. m_InUseObjects[0] = m_InUseObjects[m_InUseObjects.Count - 1];
  90. m_InUseObjects[m_InUseObjects.Count - 1] = obj;
  91. }
  92. m_LastObjectGetTime = Time.time;
  93. obj.gameObject.SetActive(true);
  94. obj.OnUse();
  95. if(m_AutoReleaseDelay != Mathf.Infinity)
  96. PoolingManager.Instance.QueueObjectRelease(obj, m_AutoReleaseDelay);
  97. return obj;
  98. }
  99. public bool TryPoolObject(PoolableObject obj)
  100. {
  101. if(!m_Initialized)
  102. {
  103. Debug.LogError("This pool can not be used, it's not initialized properly!");
  104. return false;
  105. }
  106. if(obj == null)
  107. {
  108. Debug.LogError("The object you want to pool is null!!");
  109. return false;
  110. }
  111. if(m_Id != obj.PoolId)
  112. {
  113. Debug.LogError("You want to put an object back in this pool, but it doesn't belong here!!");
  114. return false;
  115. }
  116. m_InUseObjects.Remove(obj);
  117. m_AvailableObjects.Add(obj);
  118. obj.OnReleased();
  119. obj.transform.SetParent(m_Parent);
  120. obj.gameObject.SetActive(false);
  121. return true;
  122. }
  123. private PoolableObject CreateNewObject(GameObject template, Transform parent, string poolId)
  124. {
  125. if(template == null)
  126. return null;
  127. GameObject obj = Object.Instantiate(template, parent);
  128. PoolableObject poolableObj = obj.GetComponent<PoolableObject>();
  129. if(poolableObj == null)
  130. poolableObj = obj.AddComponent<PoolableObject>();
  131. poolableObj.Init(poolId);
  132. return poolableObj;
  133. }
  134. }
  135. }