diff --git a/Scripts/System/PlacementManager.cs b/Scripts/System/PlacementManager.cs index c7a2f8b..7bbcb45 100644 --- a/Scripts/System/PlacementManager.cs +++ b/Scripts/System/PlacementManager.cs @@ -10,8 +10,68 @@ public partial class PlacementManager : Node2D { [Export] public GridManager Grid { get; set; } [Export] public BuildingRegistry Registry { get; set; } + [Export] public int MaxConcurrentBuilds { get; set; } = 6; // Make it adjustable in editor private static readonly List BuildableTiles = ["wall", "miner"]; + private readonly List _activeBuilds = new(); + private AudioStreamPlayer _completionSound; + + public override void _Ready() + { + base._Ready(); + + // Setup completion sound + _completionSound = new AudioStreamPlayer(); + AddChild(_completionSound); + var sound = GD.Load("res://Sounds/Events/ConstructionComplete.wav"); + if (sound != null) + { + _completionSound.Stream = sound; + } + } + + private void OnBuildCompleted() + { + // Remove all completed builds + _activeBuilds.RemoveAll(task => task.IsCompleted); + + // If no builds left, play the completion sound + if (_activeBuilds.Count == 0) + { + _completionSound.Play(); + } + } + + // Call this when starting a new build + private bool CanStartNewBuild() + { + // Remove completed builds + _activeBuilds.RemoveAll(task => task.IsCompleted); + return _activeBuilds.Count < MaxConcurrentBuilds; + } + + private class BuildTask : IDisposable + { + private readonly Action _onCompleted; + public bool IsCompleted { get; private set; } + + public BuildTask(Action onCompleted) + { + _onCompleted = onCompleted; + } + + public void Complete() + { + if (IsCompleted) return; + IsCompleted = true; + _onCompleted?.Invoke(); + } + + public void Dispose() + { + Complete(); + } + } private string _currentBuildingId = "wall"; private Vector2I _hoveredCell; @@ -121,6 +181,12 @@ public partial class PlacementManager : Node2D { var building = Registry.GetBuilding(_currentBuildingId); if (building == null) return; + + if (!CanStartNewBuild()) + { + // Optionally show feedback to player that build queue is full + return; + } var scene = building.Scene; var buildingInstance = (BaseTile)scene.Instantiate(); @@ -132,7 +198,11 @@ public partial class PlacementManager : Node2D Grid.OccupyArea(_hoveredCell, buildingInstance, building.Size, _currentRotation, building.Layer); if (building.BuildTime > 0f) - buildingInstance.StartConstruction(building.BuildTime); + { + var buildTask = new BuildTask(OnBuildCompleted); + _activeBuilds.Add(buildTask); + buildingInstance.StartConstruction(building.BuildTime, buildTask.Complete); + } } if (Input.IsActionPressed("destroy_tile") && diff --git a/Scripts/Tiles/BaseTile.cs b/Scripts/Tiles/BaseTile.cs index 985b666..de19fff 100644 --- a/Scripts/Tiles/BaseTile.cs +++ b/Scripts/Tiles/BaseTile.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using AceFieldNewHorizon.Scripts.System; using Godot; @@ -12,7 +13,7 @@ public partial class BaseTile : Node2D private CollisionShape2D _collisionShape; private Sprite2D _sprite; private ColorRect _progressOverlay; - private AudioStreamPlayer _completionSound; + private Action _onConstructionComplete; public override void _Ready() { @@ -21,15 +22,6 @@ public partial class BaseTile : Node2D _progressOverlay = GetNodeOrNull("ProgressOverlay"); if (_progressOverlay != null) _progressOverlay.Visible = false; - - // Setup audio player - _completionSound = new AudioStreamPlayer(); - AddChild(_completionSound); - var sound = GD.Load("res://Sounds/Events/ConstructionComplete.wav"); - if (sound != null) - { - _completionSound.Stream = sound; - } } public void SetGhostMode(bool canPlace) @@ -52,10 +44,15 @@ public partial class BaseTile : Node2D } // Building progress visualization - public void StartConstruction(float buildTime) + public void StartConstruction(float buildTime, Action onComplete = null) { - if (_progressOverlay == null || _sprite?.Texture == null) return; + if (_progressOverlay == null || _sprite?.Texture == null) + { + onComplete?.Invoke(); + return; + } + _onConstructionComplete = onComplete; var texSize = new Vector2(GridUtils.TileSize, GridUtils.TileSize); _progressOverlay.Visible = true; @@ -80,8 +77,11 @@ public partial class BaseTile : Node2D ); } - // Fade out the overlay instead of making it instantly disappear + // Fade out the overlay await FadeOutOverlay(0.5f); + + // Notify completion + _onConstructionComplete?.Invoke(); } RunProgress(); @@ -92,12 +92,6 @@ public partial class BaseTile : Node2D var elapsed = 0f; var startAlpha = _progressOverlay.Modulate.A; - // Play completion sound - if (_completionSound?.Stream != null) - { - _completionSound.Play(); - } - while (elapsed < duration) { await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame);