Added very basic chunk unloading.

WorldChunkRefactoring
Martin Felis 2023-10-08 21:38:49 +02:00
parent f8819937e1
commit 30b70d1d7a
1 changed files with 86 additions and 11 deletions

View File

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