using UnityEngine;
|
using UnityEngine.Tilemaps;
|
|
public class FogOfWar : MonoBehaviour
|
{
|
public Tilemap fogTilemap;
|
public TileBase fogTile;
|
public Transform player;
|
public int viewRadius = 5;
|
public Camera mainCamera;
|
|
private Vector3Int lastPlayerCell;
|
private const float UpdateInterval = 0.1f; // Update every 100ms
|
private float updateTimer;
|
private TileBase[,] discoveredFog; // Store the lowest opacity fog level for each tile
|
|
[System.Serializable]
|
public class FogLevel
|
{
|
public TileBase tile;
|
public float opacity;
|
}
|
public FogLevel[] fogLevels;
|
|
private void Start()
|
{
|
if (mainCamera == null)
|
mainCamera = Camera.main;
|
// Initialize the discovered fog array
|
int fogDepth = GenerateTileMap.groundDepth - 1; // Subtract 2 to account for array starting at y=-3
|
discoveredFog = new TileBase[GenerateTileMap.maxWidth + 1, fogDepth];
|
// Initialize fog using GenerateTileMap bounds
|
for (int x = 0; x <= GenerateTileMap.maxWidth; x++)
|
{
|
// Clear surface tiles (0 to -1)
|
for (int y = 0; y >= -1; y--)
|
{
|
Vector3Int tilePosition = new Vector3Int(x, y, 0);
|
fogTilemap.SetTile(tilePosition, null);
|
}
|
|
// Set fog for underground tiles (-2 and below)
|
for (int y = -2; y >= -GenerateTileMap.groundDepth; y--)
|
{
|
Vector3Int tilePosition = new Vector3Int(x, y, 0);
|
fogTilemap.SetTile(tilePosition, fogTile);
|
|
// Convert to array index (y=-2 maps to array index 0)
|
int arrayY = Mathf.Abs(y + 2);
|
discoveredFog[x, arrayY] = fogTile;
|
}
|
}
|
|
// Position the fog tilemap at the same position as the main tilemap
|
fogTilemap.transform.position = new Vector3(
|
(GenerateTileMap.maxWidth / 2) * -1,
|
-1,
|
transform.position.z
|
);
|
lastPlayerCell = fogTilemap.WorldToCell(player.position);
|
|
if (SaveSystem.isGameLoaded)
|
{
|
SaveDataMap mapState = GetComponent<SaveSystemManager>().GetMapStateFromSave();
|
if (mapState != null && mapState.fogOfWarData != null)
|
{
|
LoadFromSaveData(mapState.fogOfWarData);
|
}
|
}
|
}
|
|
private void Update()
|
{
|
updateTimer += Time.deltaTime;
|
if (updateTimer < UpdateInterval)
|
return;
|
updateTimer = 0;
|
Vector3Int playerCell = fogTilemap.WorldToCell(player.position);
|
|
// Only update if player moved to a new cell
|
if (playerCell == lastPlayerCell)
|
return;
|
|
lastPlayerCell = playerCell;
|
|
// Get camera bounds in world space
|
Vector2 cameraMin = mainCamera.ViewportToWorldPoint(new Vector3(0, 0));
|
Vector2 cameraMax = mainCamera.ViewportToWorldPoint(new Vector3(1, 1));
|
// Convert to tile coordinates
|
Vector3Int tileMin = fogTilemap.WorldToCell(cameraMin);
|
Vector3Int tileMax = fogTilemap.WorldToCell(cameraMax);
|
// Clamp to map bounds
|
tileMin.x = Mathf.Max(0, tileMin.x - viewRadius);
|
tileMin.y = Mathf.Max(-GenerateTileMap.groundDepth, tileMin.y - viewRadius);
|
tileMax.x = Mathf.Min(GenerateTileMap.maxWidth, tileMax.x + viewRadius);
|
tileMax.y = Mathf.Min(-2, tileMax.y + viewRadius);
|
|
// Clear fog around player
|
// Only check tiles within camera view
|
for (int x = tileMin.x; x <= tileMax.x; x++)
|
{
|
for (int y = tileMin.y; y <= tileMax.y; y++)
|
{
|
Vector3Int tilePosition = new Vector3Int(x, y, 0);
|
float distance = Vector2.Distance(((Vector2Int)playerCell), (Vector2Int)tilePosition);
|
|
if (distance <= viewRadius)
|
{
|
int fogIndex = Mathf.FloorToInt((distance / viewRadius) * (fogLevels.Length - 1));
|
fogIndex = Mathf.Clamp(fogIndex, 0, fogLevels.Length - 1);
|
|
TileBase newFogTile = distance <= 1 ? null : fogLevels[fogIndex].tile;
|
|
// Update the discovered state with the lowest opacity (null or lower fog index)
|
int arrayY = Mathf.Abs(y + 2); // y=-2 maps to array index 0
|
if (x >= 0 && x < discoveredFog.GetLength(0) &&
|
arrayY >= 0 && arrayY < discoveredFog.GetLength(1))
|
{
|
if (newFogTile == null)
|
{
|
discoveredFog[x, arrayY] = null;
|
}
|
else if (discoveredFog[x, arrayY] != null)
|
{
|
// Find the index of the current and new fog tiles
|
int currentIndex = System.Array.FindIndex(fogLevels, f => f.tile == discoveredFog[x, arrayY]);
|
int newIndex = System.Array.FindIndex(fogLevels, f => f.tile == newFogTile);
|
|
// Keep the lower opacity version
|
if (newIndex < currentIndex)
|
{
|
discoveredFog[x, arrayY] = newFogTile;
|
}
|
}
|
|
// Always use the discovered state
|
fogTilemap.SetTile(tilePosition, discoveredFog[x, arrayY]);
|
}
|
}
|
}
|
}
|
}
|
|
public (TileBase[,] discoveredFog, TileBase fogTile, FogLevel[] fogLevels) GetSaveValues()
|
{
|
return (discoveredFog,fogTile, fogLevels);
|
}
|
|
public void LoadFromSaveData(FogOfWarData saveData)
|
{
|
if (saveData == null || saveData.discoveredTiles == null)
|
return;
|
|
// Reset fog to full opacity
|
for (int x = 0; x < discoveredFog.GetLength(0); x++)
|
{
|
// Reset underground tiles only (-2 and below)
|
for (int y = -2; y >= -GenerateTileMap.groundDepth; y--)
|
{
|
Vector3Int tilePosition = new Vector3Int(x, y, 0);
|
fogTilemap.SetTile(tilePosition, fogTile);
|
|
int arrayY = Mathf.Abs(y + 2);
|
discoveredFog[x, arrayY] = fogTile;
|
}
|
}
|
|
// Apply saved fog states
|
foreach (FogTileData tileData in saveData.discoveredTiles)
|
{
|
if (tileData.x >= 0 && tileData.x < discoveredFog.GetLength(0) &&
|
tileData.y >= 0 && tileData.y < discoveredFog.GetLength(1))
|
{
|
TileBase tileToUse = tileData.fogLevelIndex == -1 ? null : fogLevels[tileData.fogLevelIndex].tile;
|
discoveredFog[tileData.x, tileData.y] = tileToUse;
|
|
// Convert array Y coordinate back to world Y coordinate
|
int worldY = -(tileData.y + 2); // Convert array index back to world coordinates
|
fogTilemap.SetTile(new Vector3Int(tileData.x, worldY, 0), tileToUse);
|
}
|
}
|
}
|
}
|