diff --git a/scenes/World.cs b/scenes/World.cs index 75b55ed..8b96e56 100644 --- a/scenes/World.cs +++ b/scenes/World.cs @@ -2,6 +2,7 @@ using Godot; using System; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; public class World : Spatial { @@ -9,7 +10,7 @@ public class World : Spatial private PackedScene _worldChunkScene = GD.Load("res://scenes/WorldChunk.tscn"); // constants - public const int ChunkSize = 4; + public const int ChunkSize = 16; public HexGrid HexGrid = new HexGrid(); public Spatial Chunks; public Color DebugColor; @@ -32,13 +33,16 @@ public class World : Spatial private int[] _previousCenterChunkCoord = { 0, 0 }; private Rect2 _centerChunkRect2 = new Rect2(); private Random _debugColorRandom = new Random(); - private Dictionary, WorldChunk> _worldChunks; + private Dictionary, WorldChunk> _cachedWorldChunks; + private List> _activeChunkIndices = new(); + private List> _addedChunkIndices = new(); + private List> _removedChunkIndices = new(); public World() { Debug.Assert(ChunkSize % 2 == 0); - _worldChunks = new Dictionary, WorldChunk>(); + _cachedWorldChunks = new Dictionary, WorldChunk>(); } // Called when the node enters the scene tree for the first time. @@ -52,15 +56,20 @@ public class World : Spatial public WorldChunk GetOrCreateWorldChunk(int xIndex, int yIndex, Color debugColor) { - if (_worldChunks.ContainsKey(new Tuple(xIndex, yIndex))) + if (IsTileCached(xIndex, yIndex)) { - WorldChunk cachedChunk = _worldChunks[new Tuple(xIndex, yIndex)]; + WorldChunk cachedChunk = _cachedWorldChunks[new Tuple(xIndex, yIndex)]; return cachedChunk; } return CreateWorldChunk(xIndex, yIndex, debugColor); } + private bool IsTileCached(int xIndex, int yIndex) + { + return _cachedWorldChunks.ContainsKey(new Tuple(xIndex, yIndex)); + } + private WorldChunk CreateWorldChunk(int xIndex, int yIndex, Color debugColor) { WorldChunk result = (WorldChunk)_worldChunkScene.Instance(); @@ -73,6 +82,7 @@ public class World : Spatial Vector2 planeCoordNorthEast = HexGrid.GetHexCenterFromOffset(offsetCoordNorthEast) + new Vector2(HexGrid.HexSize.x, -HexGrid.HexSize.y) * 0.5f; + result.ChunkAddress = new Vector2(xIndex, yIndex); result.PlaneRect = new Rect2( new Vector2(planeCoordSouthWest.x, planeCoordNorthEast.y), new Vector2(planeCoordNorthEast.x - planeCoordSouthWest.x, planeCoordSouthWest.y - planeCoordNorthEast.y)); @@ -82,21 +92,86 @@ public class World : Spatial Chunks.AddChild(result); Tuple chunkIndex = new Tuple(xIndex, yIndex); - _worldChunks.Add(chunkIndex, result); + _cachedWorldChunks.Add(chunkIndex, result); return result; } public void UpdateCenterChunkFromPlaneCoord(Vector2 planeCoord) { - HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord); - Vector2 chunkIndexFloatUnrounded = (centerOffsetCoord.OffsetCoords / (float)ChunkSize); - Vector2 chunkIndexFloat = (centerOffsetCoord.OffsetCoords / (float)ChunkSize).Floor(); - Tuple chunkIndex = new Tuple((int)chunkIndexFloat.x, (int)chunkIndexFloat.y); - + // mark all chunks as retired + Dictionary, WorldChunk> oldCachedChunks = new(_cachedWorldChunks); + + // set new center chunk + var chunkIndex = GetChunkTupleFromPlaneCoord(planeCoord); WorldChunk currentChunk = GetOrCreateWorldChunk(chunkIndex.Item1, chunkIndex.Item2, new Color(GD.Randf(), GD.Randf(), GD.Randf())); _centerChunkRect2 = currentChunk.PlaneRect; + + // load or create adjacent chunks + _activeChunkIndices = new List>(); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 - 1, chunkIndex.Item2 - 1)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1, chunkIndex.Item2 - 1)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 + 1, chunkIndex.Item2 - 1)); + + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 - 1, chunkIndex.Item2)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1, chunkIndex.Item2)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 + 1, chunkIndex.Item2)); + + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 - 1, chunkIndex.Item2 + 1)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1, chunkIndex.Item2 + 1)); + _activeChunkIndices.Add(new Tuple(chunkIndex.Item1 + 1, chunkIndex.Item2 + 1)); + + foreach(Tuple activeChunkIndex in _activeChunkIndices) + { + GetOrCreateWorldChunk(activeChunkIndex.Item1, activeChunkIndex.Item2, new Color(GD.Randf(), GD.Randf(), GD.Randf())); + } + + // unload retired chunks + _removedChunkIndices.Clear(); + _addedChunkIndices.Clear(); + + foreach (var cachedChunkKey in oldCachedChunks.Keys) + { + if (!_activeChunkIndices.Contains(cachedChunkKey)) + { + RemoveChunk(cachedChunkKey); + } + } + + foreach (var chunkKey in _activeChunkIndices) + { + if (!oldCachedChunks.ContainsKey(chunkKey)) + { + _addedChunkIndices.Add(chunkKey); + } + } + + GD.Print("Removed Chunks " + _removedChunkIndices.Count); + GD.Print("Added Chunks " + _addedChunkIndices.Count); + } + + private void RemoveChunk(Tuple cachedChunkKey) + { + _cachedWorldChunks.Remove(cachedChunkKey); + _removedChunkIndices.Add(cachedChunkKey); + + foreach (WorldChunk chunk in Chunks.GetChildren()) + { + if (chunk.ChunkAddress == new Vector2(cachedChunkKey.Item1, cachedChunkKey.Item2)) + { + chunk.QueueFree(); + } + } + } + + + private Tuple GetChunkTupleFromPlaneCoord(Vector2 planeCoord) + { + HexCell centerOffsetCoord = HexGrid.GetHexAt(planeCoord); + Vector2 chunkIndexFloat = (centerOffsetCoord.OffsetCoords / (float)ChunkSize).Floor(); + Tuple chunkIndex = new Tuple((int)chunkIndexFloat.x, (int)chunkIndexFloat.y); + return chunkIndex; } public void SetCenterPlaneCoord(Vector2 centerPlaneCoord)