diff --git a/Scripts/System/GridManager.cs b/Scripts/System/GridManager.cs index bf17121..4897280 100644 --- a/Scripts/System/GridManager.cs +++ b/Scripts/System/GridManager.cs @@ -1,31 +1,68 @@ #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 _grid = new(); + private Dictionary> _layers = new(); - public bool IsCellFree(Vector2I cell) + public GridManager() { - return !_grid.ContainsKey(cell); + // Initialize all layers + foreach (GridLayer layer in Enum.GetValues(typeof(GridLayer))) + { + _layers[layer] = new Dictionary(); + } } - public void OccupyCell(Vector2I cell, Node2D building) + public bool IsCellFree(Vector2I cell, GridLayer layer = GridLayer.Building) { - _grid[cell] = building; + return !_layers[layer].ContainsKey(cell); } - public void FreeCell(Vector2I cell) + public void OccupyCell(Vector2I cell, Node2D building, GridLayer layer = GridLayer.Building) { - _grid.Remove(cell); + _layers[layer][cell] = building; } - public Node2D? GetBuildingAtCell(Vector2I cell) + public void FreeCell(Vector2I cell, GridLayer layer = GridLayer.Building) { - return _grid.GetValueOrDefault(cell); + 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; } } diff --git a/Scripts/System/PlacementManager.cs b/Scripts/System/PlacementManager.cs index 7dd4021..608e1fb 100644 --- a/Scripts/System/PlacementManager.cs +++ b/Scripts/System/PlacementManager.cs @@ -1,3 +1,4 @@ +using System; using AceFieldNewHorizon.Scripts.Tiles; using Godot; @@ -8,14 +9,16 @@ public partial class PlacementManager : Node2D [Export] public GridManager Grid { get; set; } [Export] public BuildingRegistry Registry { get; set; } - private string _currentBuildingId = "miner"; - + private string _currentBuildingId = "wall"; + private GridLayer _currentLayer = GridLayer.Building; // Default layer private Vector2I _hoveredCell; private BaseTile _ghostBuilding; + private float _currentRotation = 0f; - public void SetCurrentBuilding(string buildingId) + public void SetCurrentBuilding(string buildingId, GridLayer layer = GridLayer.Building) { _currentBuildingId = buildingId; + _currentLayer = layer; // Replace ghost immediately if (_ghostBuilding == null) return; @@ -23,10 +26,17 @@ public partial class PlacementManager : Node2D _ghostBuilding = null; } - // Add this field to PlacementManager - private float _currentRotation = 0f; + public void SetCurrentLayer(GridLayer layer) + { + _currentLayer = layer; + // Update ghost building if needed + if (_ghostBuilding != null) + { + _ghostBuilding.QueueFree(); + _ghostBuilding = null; + } + } - // Add this method to handle rotation private void RotateGhost(bool reverse = false) { if (_ghostBuilding == null) return; @@ -56,6 +66,8 @@ public partial class PlacementManager : Node2D _ghostBuilding = (BaseTile)scene.Instantiate(); _ghostBuilding.SetGhostMode(true); _ghostBuilding.RotationDegrees = _currentRotation; + _ghostBuilding.ZAsRelative = false; + _ghostBuilding.ZIndex = (int)_currentLayer; // Use layer as Z-index AddChild(_ghostBuilding); } @@ -68,17 +80,18 @@ public partial class PlacementManager : Node2D Position = centerPos, CollideWithBodies = true, CollideWithAreas = true, - CollisionMask = uint.MaxValue // check against all layers/masks - // Exclude = new Godot.Collections.Array() // optional, see below + CollisionMask = uint.MaxValue }; var collision = spaceState.IntersectPoint(query, 8); - var canPlace = Grid.IsCellFree(_hoveredCell) && collision.Count == 0; + + // Check if the current cell is free in the current layer + var canPlace = Grid.IsCellFree(_hoveredCell, _currentLayer) && + !Grid.IsAnyCellOccupied(_hoveredCell, GetBlockingLayers()); _ghostBuilding.Position = placementPos; _ghostBuilding.SetGhostMode(canPlace); - // Left click to place if (Input.IsActionPressed("build_tile") && canPlace) { @@ -87,26 +100,42 @@ public partial class PlacementManager : Node2D _ghostBuilding.FinalizePlacement(); _ghostBuilding.RotationDegrees = _currentRotation; + _ghostBuilding.ZIndex = (int)_currentLayer; var buildingData = Registry.GetBuilding(_currentBuildingId); - Grid.OccupyCell(_hoveredCell, _ghostBuilding); + Grid.OccupyCell(_hoveredCell, _ghostBuilding, _currentLayer); if (buildingData is { BuildTime: > 0f }) _ghostBuilding.StartConstruction(buildingData.BuildTime); + // Create new ghost for next placement _ghostBuilding = (BaseTile)scene.Instantiate(); _ghostBuilding.SetGhostMode(true); _ghostBuilding.RotationDegrees = _currentRotation; + _ghostBuilding.ZAsRelative = false; + _ghostBuilding.ZIndex = (int)_currentLayer; AddChild(_ghostBuilding); } - if (Input.IsActionPressed("destroy_tile") && !Grid.IsCellFree(_hoveredCell)) + if (Input.IsActionPressed("destroy_tile") && !Grid.IsCellFree(_hoveredCell, _currentLayer)) { - // Right click to destroy - var building = Grid.GetBuildingAtCell(_hoveredCell); + // Right click to destroy from current layer + var building = Grid.GetBuildingAtCell(_hoveredCell, _currentLayer); if (building == null) return; building.QueueFree(); - Grid.FreeCell(_hoveredCell); + Grid.FreeCell(_hoveredCell, _currentLayer); } } + + // Define which layers should block placement + private GridLayer[] GetBlockingLayers() + { + return _currentLayer switch + { + GridLayer.Ground => new[] { GridLayer.Ground }, + GridLayer.Building => new[] { GridLayer.Ground, GridLayer.Building }, + GridLayer.Decoration => new[] { GridLayer.Ground, GridLayer.Building, GridLayer.Decoration }, + _ => [] + }; + } } \ No newline at end of file