using System.Numerics; using AceFieldNewHorizon.Scripts.System; using Godot; using Vector2 = Godot.Vector2; namespace AceFieldNewHorizon.Scripts.Tiles; public partial class BaseTile : Node2D { private CollisionShape2D _collisionShape; private Sprite2D _sprite; private ColorRect _progressOverlay; public override void _Ready() { _collisionShape = GetNodeOrNull("CollisionShape2D"); _sprite = GetNodeOrNull("Sprite2D"); _progressOverlay = GetNodeOrNull("ProgressOverlay"); if (_progressOverlay != null) _progressOverlay.Visible = false; } public void SetGhostMode(bool canPlace) { if (_collisionShape != null) _collisionShape.Disabled = true; if (_sprite != null) _sprite.Modulate = canPlace ? new Color(0, 1, 0, 0.5f) : new Color(1, 0, 0, 0.5f); } public void FinalizePlacement() { if (_collisionShape != null) _collisionShape.Disabled = false; if (_sprite != null) _sprite.Modulate = Colors.White; } // Building progress visualization public void StartConstruction(float buildTime) { if (_progressOverlay == null || _sprite?.Texture == null) return; var texSize = new Vector2(GridUtils.TileSize, GridUtils.TileSize); _progressOverlay.Visible = true; _progressOverlay.Color = new Color(0, 0, 1, 0.4f); // semi-transparent blue async void RunProgress() { var elapsed = 0f; while (elapsed < buildTime) { await ToSignal(GetTree(), SceneTree.SignalName.ProcessFrame); elapsed += (float)GetProcessDeltaTime(); var ratio = Mathf.Clamp(elapsed / buildTime, 0, 1); // Fill from bottom to top, aligned with sprite center pivot _progressOverlay.Size = new Vector2(texSize.X, texSize.Y * ratio); _progressOverlay.Position = new Vector2( -texSize.X / 2, // align left edge texSize.Y / 2 - _progressOverlay.Size.Y // move upward ); } _progressOverlay.Visible = false; } RunProgress(); } }