#nullable enable using System; using System.Collections.Generic; using Godot; namespace AceFieldNewHorizon.Scripts.System; public enum GridLayer { Ground, // Base layer (e.g., terrain, floors) Building, // Main building layer Decoration // Additional layer for decorations, effects, etc. } public partial class GridManager : Node { private Dictionary> _layers = new(); public GridManager() { // Initialize all layers foreach (GridLayer layer in Enum.GetValues(typeof(GridLayer))) { _layers[layer] = new Dictionary(); } } public bool IsCellFree(Vector2I cell, GridLayer layer = GridLayer.Building) { return !_layers[layer].ContainsKey(cell); } public void OccupyCell(Vector2I cell, Node2D building, GridLayer layer = GridLayer.Building) { _layers[layer][cell] = building; } public void FreeCell(Vector2I cell, GridLayer layer = GridLayer.Building) { if (_layers[layer].ContainsKey(cell)) _layers[layer].Remove(cell); } public Node2D? GetBuildingAtCell(Vector2I cell, GridLayer layer = GridLayer.Building) { return _layers[layer].GetValueOrDefault(cell); } public bool IsAnyCellOccupied(Vector2I cell, params GridLayer[] layers) { if (layers.Length == 0) { // Check all layers if none specified foreach (var layer in _layers.Values) { if (layer.ContainsKey(cell)) return true; } return false; } foreach (var layer in layers) { if (_layers[layer].ContainsKey(cell)) return true; } return false; } } public static class GridUtils { public const int TileSize = 54; public static Vector2I WorldToGrid(Vector2 pos) { return new Vector2I( Mathf.FloorToInt(pos.X / TileSize), Mathf.FloorToInt(pos.Y / TileSize) ); } public static Vector2 GridToWorld(Vector2I cell) { return new Vector2( cell.X * TileSize, cell.Y * TileSize ); } }