miepzerino
2025-04-03 4f1ed3919b0ee3f89dbcbacf49990888a7d9274a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
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 = SaveSystem.LoadMapState();
            if (mapState != null && mapState.fogOfWarData != null)
            {
                GetComponent<FogOfWar>().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 FogOfWarData GetSaveData()
    {
        FogOfWarData saveData = new FogOfWarData();
 
        for (int x = 0; x < discoveredFog.GetLength(0); x++)
        {
            for (int y = 0; y < discoveredFog.GetLength(1); y++)
            {
                TileBase currentTile = discoveredFog[x, y];
                if (currentTile == null || currentTile != fogTile) // Only save revealed tiles
                {
                    FogTileData tileData = new FogTileData
                    {
                        x = x,
                        y = y,
                        fogLevelIndex = currentTile == null ? -1 : System.Array.FindIndex(fogLevels, f => f.tile == currentTile)
                    };
                    saveData.discoveredTiles.Add(tileData);
                }
            }
        }
 
        return saveData;
    }
 
    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);
            }
        }
    }
}