TileInstanceSource.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using DunGen.Pooling;
  2. using UnityEngine;
  3. namespace DunGen.Generation
  4. {
  5. public delegate void TileInstanceSpawnedDelegate(Tile tilePrefab, Tile tileInstance, bool fromPool);
  6. public delegate void TileInstanceDespawnedDelegate(Tile tileInstance);
  7. /// <summary>
  8. /// A class responsible for the spawning and despawning of tiles
  9. /// </summary>
  10. public class TileInstanceSource
  11. {
  12. public event TileInstanceSpawnedDelegate TileInstanceSpawned;
  13. public event TileInstanceDespawnedDelegate TileInstanceDespawned;
  14. protected readonly BucketedObjectPool<Tile, Tile> tilePool;
  15. protected bool enableTilePooling;
  16. protected GameObject dungeonRoot;
  17. protected Transform tilePoolRoot;
  18. protected TilePoolPreloader tilePoolPreloader;
  19. public TileInstanceSource()
  20. {
  21. tilePool = new BucketedObjectPool<Tile, Tile>(
  22. objectFactory: template =>
  23. {
  24. var tileObj = Object.Instantiate(template);
  25. if (tileObj.TryGetComponent<Tile>(out var tile))
  26. tile.RefreshTileEventReceivers();
  27. return tileObj;
  28. });
  29. }
  30. /// <summary>
  31. /// Initialises the TileInstanceSource
  32. /// </summary>
  33. /// <param name="enableTilePooling">Should tile pooling be used?</param>
  34. /// <param name="dungeonRoot">The root GameObject of the dungeon</param>
  35. public virtual void Initialise(bool enableTilePooling, GameObject dungeonRoot)
  36. {
  37. this.enableTilePooling = enableTilePooling;
  38. this.dungeonRoot = dungeonRoot;
  39. if (!enableTilePooling)
  40. return;
  41. // Try to find a TilePoolPreloader in the scene, and pre-warm the pool with its contents
  42. if (tilePoolPreloader == null)
  43. TryPreloadTilePool();
  44. // Create a GameObject to parent all pooled tiles to
  45. if (tilePoolRoot == null)
  46. {
  47. var tilePoolObj = new GameObject("Tile Pool");
  48. tilePoolObj.SetActive(false);
  49. tilePoolRoot = tilePoolObj.transform;
  50. }
  51. }
  52. protected void TryPreloadTilePool()
  53. {
  54. tilePoolPreloader = UnityUtil.FindObjectByType<TilePoolPreloader>();
  55. if(tilePoolPreloader == null)
  56. return;
  57. // Make the tile preloader the pool root
  58. tilePoolPreloader.gameObject.SetActive(false);
  59. tilePoolRoot = tilePoolPreloader.transform;
  60. // Insert each preloaded tile into the correct bucket in the pool
  61. foreach (var entry in tilePoolPreloader.Entries)
  62. {
  63. var prefab = entry.TilePrefab;
  64. if (prefab == null)
  65. continue;
  66. var instances = tilePoolPreloader.GetTileInstancesForPrefab(prefab);
  67. if(instances == null)
  68. continue;
  69. foreach (var instance in instances)
  70. {
  71. // The tile should be active as the tile pool root itself is inactive
  72. instance.gameObject.SetActive(true);
  73. instance.RefreshTileEventReceivers();
  74. tilePool.InsertObject(prefab, instance);
  75. }
  76. }
  77. }
  78. /// <summary>
  79. /// Spawns a tile at the specified position and rotation. If pooling is enabled, the tile will
  80. /// be taken from the pool. If pooling is disabled, or the pool is empty, a new tile will be instantiated
  81. /// </summary>
  82. /// <param name="tilePrefab">Tile prefab to spawn</param>
  83. /// <param name="position">World-space position</param>
  84. /// <param name="rotation">World-space rotation</param>
  85. /// <returns>The spawned tile instance</returns>
  86. public virtual Tile SpawnTile(Tile tilePrefab, Vector3 position, Quaternion rotation)
  87. {
  88. if (enableTilePooling)
  89. {
  90. bool fromPool = tilePool.TryTakeObject(tilePrefab, out var tile);
  91. var tileTransform = tile.transform;
  92. tileTransform.parent = dungeonRoot.transform;
  93. tileTransform.localPosition = position;
  94. tileTransform.localRotation = rotation;
  95. tile.TileSpawned();
  96. TileInstanceSpawned?.Invoke(tilePrefab, tile, fromPool);
  97. return tile;
  98. }
  99. else
  100. {
  101. var tileObj = GameObject.Instantiate(tilePrefab, position, rotation, dungeonRoot.transform);
  102. if (tileObj.TryGetComponent<Tile>(out var tile))
  103. {
  104. tile.RefreshTileEventReceivers();
  105. tile.TileSpawned();
  106. TileInstanceSpawned?.Invoke(tilePrefab, tile, false);
  107. }
  108. return tileObj;
  109. }
  110. }
  111. /// <summary>
  112. /// Despawns a tile. If pooling is enabled, the tile will be returned to the pool.
  113. /// If pooling is disabled, the tile will be destroyed
  114. /// </summary>
  115. /// <param name="tileInstance">The tile instance to despawn</param>
  116. public virtual void DespawnTile(Tile tileInstance)
  117. {
  118. bool returnedToPool = false;
  119. // Try to return the tile to the pool
  120. if (enableTilePooling)
  121. {
  122. returnedToPool = tilePool.ReturnObject(tileInstance);
  123. if (returnedToPool)
  124. {
  125. tileInstance.transform.parent = tilePoolRoot;
  126. tileInstance.TileDespawned();
  127. TileInstanceDespawned?.Invoke(tileInstance);
  128. }
  129. }
  130. // If we can't return the tile to the pool, or pooling was disabled, destroy the tile instead
  131. if (!returnedToPool)
  132. {
  133. tileInstance.TileDespawned();
  134. TileInstanceDespawned?.Invoke(tileInstance);
  135. GameObject.DestroyImmediate(tileInstance.gameObject);
  136. }
  137. }
  138. }
  139. }