using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; // TODO: The actual building logic and the construction logic should be separated! [RequireComponent(typeof(BoxCollider2D), typeof(SpriteRenderer))] public class Building : MonoBehaviour { private struct WorkOrder { public float startTime; public float duration; public Action completed; } [Serializable] public struct UnitCommand { public Unit unit; public Key keyControl; public int cost; public float buildDuration; } [NonSerialized] public BoxCollider2D buildingCollider; public int maxQueueCount; public float constructionTime; public bool startBuilt; public int buildingCost; public List buildableUnits; [NonSerialized] public bool isUnderConstruction = true; private readonly Queue _workQueue = new Queue(); private WorkOrder _currentWorkOrder; private bool _hasCurrentWorkOrder; // In seconds. private float _currentConstructionProgress; private readonly Color _constructionColor = Color.black; private SpriteRenderer _sprite; private Transform _transform; private void Start() { buildingCollider = GetComponent(); _sprite = GetComponent(); isUnderConstruction = !startBuilt; _transform = transform; } public void UpdateBuildProgress(float amount) { if (isUnderConstruction) { _currentConstructionProgress += amount; if (_currentConstructionProgress >= constructionTime) { isUnderConstruction = false; } _sprite.color = Color.Lerp(_constructionColor, Color.white, _currentConstructionProgress / constructionTime); } } private void Update() { if (_hasCurrentWorkOrder) { if (Time.time > _currentWorkOrder.startTime + _currentWorkOrder.duration) { _currentWorkOrder.completed(); _hasCurrentWorkOrder = false; } } else { // Could probably do all this once we complete the order. // Would also need to do it when we receive an order. if (_workQueue.Count > 0) { _currentWorkOrder = _workQueue.Dequeue(); _currentWorkOrder.startTime = Time.time; _hasCurrentWorkOrder = true; } } } public void ProcessKeyInput(Key key) { if (isUnderConstruction) { return; } foreach (var command in buildableUnits) { if (command.keyControl == key) { if (command.cost > Team.Minerals) { // TODO: announcer. Debug.LogWarning("You've not enough minerals"); break; } if (maxQueueCount > _workQueue.Count) { Team.Minerals -= command.cost; _workQueue.Enqueue(new WorkOrder { startTime = Time.time, duration = command.buildDuration, completed = () => { var unitGo = Instantiate(command.unit, _transform.position, _transform.rotation); Team.AllUnits.Add(unitGo); } }); } } } } }