MazeFogOfWar.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. /// <summary>
  4. /// Manages fog of war for the maze - only shows explored areas
  5. /// AI entities can only see areas they've visited or are within their vision range
  6. /// </summary>
  7. public class MazeFogOfWar : MonoBehaviour
  8. {
  9. [Header("Fog Settings")]
  10. [SerializeField] private MazeController mazeController;
  11. [Header("Rendering")]
  12. [SerializeField] private ChunkedMazeRenderer chunkedRenderer;
  13. [SerializeField] private MeshMazeRenderer meshRenderer;
  14. [SerializeField] private Color fogColor = new Color(0.1f, 0.1f, 0.1f, 0.8f);
  15. [SerializeField] private Material fogMaterial;
  16. private HashSet<Vector2Int> exploredTiles = new();
  17. private Dictionary<GameObject, HashSet<Vector2Int>> entityVisionRanges = new();
  18. void Start()
  19. {
  20. if (fogMaterial == null)
  21. {
  22. CreateFogMaterial();
  23. }
  24. if (meshRenderer == null)
  25. {
  26. meshRenderer = GetComponent<MeshMazeRenderer>() ?? FindFirstObjectByType<MeshMazeRenderer>();
  27. }
  28. }
  29. /// <summary>
  30. /// Marks a tile as explored
  31. /// </summary>
  32. public void ExploreTile(Vector2Int tilePos)
  33. {
  34. exploredTiles.Add(tilePos);
  35. UpdateRendering();
  36. }
  37. /// <summary>
  38. /// Marks multiple tiles as explored
  39. /// </summary>
  40. public void ExploreTiles(IEnumerable<Vector2Int> tiles)
  41. {
  42. foreach (var tile in tiles)
  43. {
  44. exploredTiles.Add(tile);
  45. }
  46. UpdateRendering();
  47. }
  48. /// <summary>
  49. /// Updates vision range for an entity
  50. /// </summary>
  51. public void UpdateEntityVision(GameObject entity, Vector2Int position, float range)
  52. {
  53. HashSet<Vector2Int> visibleTiles = GetVisibleTiles(position, range);
  54. if (!entityVisionRanges.ContainsKey(entity))
  55. {
  56. entityVisionRanges[entity] = new HashSet<Vector2Int>();
  57. }
  58. // Remove old vision
  59. foreach (var tile in entityVisionRanges[entity])
  60. {
  61. if (!exploredTiles.Contains(tile) && !IsTileVisibleByOtherEntities(tile))
  62. {
  63. // Tile should be hidden
  64. }
  65. }
  66. // Add new vision
  67. entityVisionRanges[entity] = visibleTiles;
  68. foreach (var tile in visibleTiles)
  69. {
  70. exploredTiles.Add(tile);
  71. }
  72. UpdateRendering();
  73. }
  74. /// <summary>
  75. /// Gets all tiles visible from a position within range
  76. /// </summary>
  77. private HashSet<Vector2Int> GetVisibleTiles(Vector2Int center, float range)
  78. {
  79. HashSet<Vector2Int> visible = new();
  80. var maze = mazeController.GetCurrentMaze();
  81. if (maze == null) return visible;
  82. int rangeInt = Mathf.CeilToInt(range);
  83. for (int x = center.x - rangeInt; x <= center.x + rangeInt; x++)
  84. {
  85. for (int y = center.y - rangeInt; y <= center.y + rangeInt; y++)
  86. {
  87. Vector2Int tilePos = new Vector2Int(x, y);
  88. if (Vector2Int.Distance(center, tilePos) <= range)
  89. {
  90. if (maze.IsInBounds(x, y) && HasLineOfSight(center, tilePos))
  91. {
  92. visible.Add(tilePos);
  93. }
  94. }
  95. }
  96. }
  97. return visible;
  98. }
  99. /// <summary>
  100. /// Checks if there's line of sight between two points
  101. /// </summary>
  102. private bool HasLineOfSight(Vector2Int from, Vector2Int to)
  103. {
  104. var maze = mazeController.GetCurrentMaze();
  105. if (maze == null) return false;
  106. // Simple line of sight check - can be enhanced with proper raycasting
  107. Vector2Int delta = to - from;
  108. int steps = Mathf.Max(Mathf.Abs(delta.x), Mathf.Abs(delta.y));
  109. for (int i = 1; i < steps; i++)
  110. {
  111. float t = (float)i / steps;
  112. Vector2Int checkPos = new Vector2Int(
  113. Mathf.RoundToInt(from.x + delta.x * t),
  114. Mathf.RoundToInt(from.y + delta.y * t)
  115. );
  116. if (!maze.IsWalkable(checkPos.x, checkPos.y))
  117. {
  118. return false;
  119. }
  120. }
  121. return true;
  122. }
  123. /// <summary>
  124. /// Checks if a tile is visible by any other entity
  125. /// </summary>
  126. private bool IsTileVisibleByOtherEntities(Vector2Int tile)
  127. {
  128. foreach (var vision in entityVisionRanges.Values)
  129. {
  130. if (vision.Contains(tile))
  131. {
  132. return true;
  133. }
  134. }
  135. return false;
  136. }
  137. /// <summary>
  138. /// Updates the rendering to show only explored areas
  139. /// </summary>
  140. private void UpdateRendering()
  141. {
  142. if (chunkedRenderer != null)
  143. {
  144. // The chunked renderer will handle showing/hiding tiles based on exploration
  145. chunkedRenderer.RefreshVisibleChunks();
  146. }
  147. if (meshRenderer != null)
  148. {
  149. meshRenderer.RefreshFogOfWar();
  150. }
  151. }
  152. /// <summary>
  153. /// Creates a default fog material
  154. /// </summary>
  155. private void CreateFogMaterial()
  156. {
  157. fogMaterial = new Material(Shader.Find("Sprites/Default"));
  158. fogMaterial.color = fogColor;
  159. }
  160. /// <summary>
  161. /// Checks if a tile is explored
  162. /// </summary>
  163. public bool IsTileExplored(Vector2Int tile)
  164. {
  165. return exploredTiles.Contains(tile);
  166. }
  167. /// <summary>
  168. /// Gets all explored tiles
  169. /// </summary>
  170. public HashSet<Vector2Int> GetExploredTiles()
  171. {
  172. return new HashSet<Vector2Int>(exploredTiles);
  173. }
  174. /// <summary>
  175. /// Removes an entity from vision tracking
  176. /// </summary>
  177. public void RemoveEntity(GameObject entity)
  178. {
  179. entityVisionRanges.Remove(entity);
  180. UpdateRendering();
  181. }
  182. }