using UnityEngine;
using System.Collections.Generic;
///
/// Manages fog of war for the maze - only shows explored areas
/// AI entities can only see areas they've visited or are within their vision range
///
public class MazeFogOfWar : MonoBehaviour
{
[Header("Fog Settings")]
[SerializeField] private MazeController mazeController;
[Header("Rendering")]
[SerializeField] private ChunkedMazeRenderer chunkedRenderer;
[SerializeField] private MeshMazeRenderer meshRenderer;
[SerializeField] private Color fogColor = new Color(0.1f, 0.1f, 0.1f, 0.8f);
[SerializeField] private Material fogMaterial;
private HashSet exploredTiles = new();
private Dictionary> entityVisionRanges = new();
void Start()
{
if (fogMaterial == null)
{
CreateFogMaterial();
}
if (meshRenderer == null)
{
meshRenderer = GetComponent() ?? FindFirstObjectByType();
}
}
///
/// Marks a tile as explored
///
public void ExploreTile(Vector2Int tilePos)
{
exploredTiles.Add(tilePos);
UpdateRendering();
}
///
/// Marks multiple tiles as explored
///
public void ExploreTiles(IEnumerable tiles)
{
foreach (var tile in tiles)
{
exploredTiles.Add(tile);
}
UpdateRendering();
}
///
/// Updates vision range for an entity
///
public void UpdateEntityVision(GameObject entity, Vector2Int position, float range)
{
HashSet visibleTiles = GetVisibleTiles(position, range);
if (!entityVisionRanges.ContainsKey(entity))
{
entityVisionRanges[entity] = new HashSet();
}
// Remove old vision
foreach (var tile in entityVisionRanges[entity])
{
if (!exploredTiles.Contains(tile) && !IsTileVisibleByOtherEntities(tile))
{
// Tile should be hidden
}
}
// Add new vision
entityVisionRanges[entity] = visibleTiles;
foreach (var tile in visibleTiles)
{
exploredTiles.Add(tile);
}
UpdateRendering();
}
///
/// Gets all tiles visible from a position within range
///
private HashSet GetVisibleTiles(Vector2Int center, float range)
{
HashSet visible = new();
var maze = mazeController.GetCurrentMaze();
if (maze == null) return visible;
int rangeInt = Mathf.CeilToInt(range);
for (int x = center.x - rangeInt; x <= center.x + rangeInt; x++)
{
for (int y = center.y - rangeInt; y <= center.y + rangeInt; y++)
{
Vector2Int tilePos = new Vector2Int(x, y);
if (Vector2Int.Distance(center, tilePos) <= range)
{
if (maze.IsInBounds(x, y) && HasLineOfSight(center, tilePos))
{
visible.Add(tilePos);
}
}
}
}
return visible;
}
///
/// Checks if there's line of sight between two points
///
private bool HasLineOfSight(Vector2Int from, Vector2Int to)
{
var maze = mazeController.GetCurrentMaze();
if (maze == null) return false;
// Simple line of sight check - can be enhanced with proper raycasting
Vector2Int delta = to - from;
int steps = Mathf.Max(Mathf.Abs(delta.x), Mathf.Abs(delta.y));
for (int i = 1; i < steps; i++)
{
float t = (float)i / steps;
Vector2Int checkPos = new Vector2Int(
Mathf.RoundToInt(from.x + delta.x * t),
Mathf.RoundToInt(from.y + delta.y * t)
);
if (!maze.IsWalkable(checkPos.x, checkPos.y))
{
return false;
}
}
return true;
}
///
/// Checks if a tile is visible by any other entity
///
private bool IsTileVisibleByOtherEntities(Vector2Int tile)
{
foreach (var vision in entityVisionRanges.Values)
{
if (vision.Contains(tile))
{
return true;
}
}
return false;
}
///
/// Updates the rendering to show only explored areas
///
private void UpdateRendering()
{
if (chunkedRenderer != null)
{
// The chunked renderer will handle showing/hiding tiles based on exploration
chunkedRenderer.RefreshVisibleChunks();
}
if (meshRenderer != null)
{
meshRenderer.RefreshFogOfWar();
}
}
///
/// Creates a default fog material
///
private void CreateFogMaterial()
{
fogMaterial = new Material(Shader.Find("Sprites/Default"));
fogMaterial.color = fogColor;
}
///
/// Checks if a tile is explored
///
public bool IsTileExplored(Vector2Int tile)
{
return exploredTiles.Contains(tile);
}
///
/// Gets all explored tiles
///
public HashSet GetExploredTiles()
{
return new HashSet(exploredTiles);
}
///
/// Removes an entity from vision tracking
///
public void RemoveEntity(GameObject entity)
{
entityVisionRanges.Remove(entity);
UpdateRendering();
}
}